summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@theqtcompany.com>2015-07-10 14:08:29 +0200
committerEike Ziller <eike.ziller@theqtcompany.com>2015-07-10 14:08:29 +0200
commitd6da70916d566bec517aedeeae3f224b8d0489a1 (patch)
tree55c20439f5c65a81647eb7999a25c472d20c7fc5
parentc69d3ded6b67b5501b9caf0d6f29148f389007ad (diff)
parenta32a9b3d2a82d38edde1b4b55cbdececd7f5333d (diff)
downloadqt-creator-d6da70916d566bec517aedeeae3f224b8d0489a1.tar.gz
Merge remote-tracking branch 'origin/3.5'
-rw-r--r--doc/images/qmldesigner-new-project.pngbin15297 -> 15278 bytes
-rw-r--r--doc/images/qtcreator-keyboard-shortcuts.pngbin15204 -> 18669 bytes
-rw-r--r--doc/images/qtcreator-new-qt-quick-project-wizard.pngbin15329 -> 15356 bytes
-rw-r--r--doc/src/editors/creator-editors.qdoc16
-rw-r--r--doc/src/howto/creator-cli.qdoc12
-rw-r--r--doc/src/howto/creator-external-tools.qdoc3
-rw-r--r--doc/src/howto/creator-keyboard-shortcuts.qdoc15
-rw-r--r--doc/src/projects/creator-projects-creating.qdoc6
-rw-r--r--doc/src/qtquick/qtquick-creating.qdoc4
-rw-r--r--qtcreator.pri6
-rw-r--r--qtcreator.qbs4
-rwxr-xr-xscripts/deployqt.py33
-rwxr-xr-xscripts/deployqtHelper_mac.sh6
-rwxr-xr-xscripts/unixdeployqt.sh100
-rw-r--r--share/qtcreator/debugger/dumper.py36
-rw-r--r--share/qtcreator/debugger/gdbbridge.py2
-rw-r--r--share/qtcreator/debugger/qttypes.py17
-rw-r--r--share/qtcreator/static.pro6
-rw-r--r--share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json14
-rw-r--r--share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json14
-rw-r--r--src/plugins/autotoolsprojectmanager/autotoolsproject.cpp29
-rw-r--r--src/plugins/autotoolsprojectmanager/makefileparser.cpp44
-rw-r--r--src/plugins/autotoolsprojectmanager/makefileparser.h8
-rw-r--r--src/plugins/clangcodemodel/clangeditordocumentparser.h7
-rw-r--r--src/plugins/clangcodemodel/clangmodelmanagersupport.cpp7
-rw-r--r--src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp116
-rw-r--r--src/plugins/cpptools/abstracteditorsupport.cpp5
-rw-r--r--src/plugins/cpptools/abstracteditorsupport.h1
-rw-r--r--src/plugins/cpptools/baseeditordocumentparser.h2
-rw-r--r--src/plugins/cpptools/baseeditordocumentprocessor.h2
-rw-r--r--src/plugins/cpptools/builtineditordocumentprocessor.h1
-rw-r--r--src/plugins/cpptools/cppeditoroutline.h1
-rw-r--r--src/plugins/cpptools/cppmodelmanager.cpp11
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h6
-rw-r--r--src/plugins/cpptools/cppsemanticinfoupdater.h1
-rw-r--r--src/plugins/cpptools/semantichighlighter.h1
-rw-r--r--src/plugins/debugger/debugger.qbs7
-rw-r--r--src/plugins/debugger/qml/baseqmldebuggerclient.cpp83
-rw-r--r--src/plugins/debugger/qml/baseqmldebuggerclient.h111
-rw-r--r--src/plugins/debugger/qml/qml.pri10
-rw-r--r--src/plugins/debugger/qml/qmladapter.cpp242
-rw-r--r--src/plugins/debugger/qml/qmladapter.h107
-rw-r--r--src/plugins/debugger/qml/qmlengine.cpp2372
-rw-r--r--src/plugins/debugger/qml/qmlengine.h92
-rw-r--r--src/plugins/debugger/qml/qmlengineutils.cpp311
-rw-r--r--src/plugins/debugger/qml/qmlengineutils.h (renamed from tests/manual/qml/testfiles/images.qml)38
-rw-r--r--src/plugins/debugger/qml/qmlinspectoradapter.cpp39
-rw-r--r--src/plugins/debugger/qml/qmlinspectoradapter.h10
-rw-r--r--src/plugins/debugger/qml/qmlinspectoragent.cpp1
-rw-r--r--src/plugins/debugger/qml/qmlv8debuggerclient.cpp1799
-rw-r--r--src/plugins/debugger/qml/qmlv8debuggerclient.h130
-rw-r--r--src/plugins/debugger/qml/qscriptdebuggerclient.cpp606
-rw-r--r--src/plugins/debugger/qml/qscriptdebuggerclient.h99
-rw-r--r--src/plugins/debugger/watchhandler.cpp5
-rw-r--r--src/plugins/debugger/watchhandler.h2
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp6
-rw-r--r--src/plugins/qbsprojectmanager/qbsproject.cpp2
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp11
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp9
-rw-r--r--src/plugins/qtsupport/uicodemodelsupport.cpp112
-rw-r--r--src/plugins/qtsupport/uicodemodelsupport.h4
-rw-r--r--tests/auto/debugger/tst_dumpers.cpp8
-rw-r--r--tests/manual/qml/testfiles/components/MyButton.qml37
-rw-r--r--tests/manual/qml/testfiles/empty.qml36
-rw-r--r--tests/manual/qml/testfiles/flipable.qml43
-rw-r--r--tests/manual/qml/testfiles/helloworld.qml41
-rw-r--r--tests/manual/qml/testfiles/helloworld_inverted.qml43
-rw-r--r--tests/manual/qml/testfiles/images/qtcreator.icobin20929 -> 0 bytes
-rw-r--r--tests/manual/qml/testfiles/images/qtcreator.jpgbin9489 -> 0 bytes
-rw-r--r--tests/manual/qml/testfiles/images/qtcreator.pngbin12498 -> 0 bytes
-rw-r--r--tests/manual/qml/testfiles/listmodel.qml40
-rw-r--r--tests/manual/qml/testfiles/listview.qml74
-rw-r--r--tests/manual/qml/testfiles/states.qml74
-rw-r--r--tests/manual/qml/testfiles/subcomponent.qml47
-rw-r--r--tests/manual/qml/testfiles/testfiles.qmlproject16
-rw-r--r--tests/manual/qml/testfiles/usingbutton.qml41
-rw-r--r--tests/manual/qml/testfiles/webview.qml43
-rw-r--r--tests/system/objects.map3
-rw-r--r--tests/system/shared/project.py29
-rw-r--r--tests/system/shared/project_explorer.py8
-rw-r--r--tests/system/suite_debugger/tst_qml_js_console/test.py14
-rw-r--r--tests/system/suite_debugger/tst_qml_locals/test.py22
-rw-r--r--tests/system/suite_qtquick/tst_qtquick_creation/test.py40
-rw-r--r--tests/system/suite_qtquick/tst_qtquick_creation3/test.py30
84 files changed, 2736 insertions, 4697 deletions
diff --git a/doc/images/qmldesigner-new-project.png b/doc/images/qmldesigner-new-project.png
index 40baa55739..1619fd18b3 100644
--- a/doc/images/qmldesigner-new-project.png
+++ b/doc/images/qmldesigner-new-project.png
Binary files differ
diff --git a/doc/images/qtcreator-keyboard-shortcuts.png b/doc/images/qtcreator-keyboard-shortcuts.png
index 514c17eb8a..064ba04fa8 100644
--- a/doc/images/qtcreator-keyboard-shortcuts.png
+++ b/doc/images/qtcreator-keyboard-shortcuts.png
Binary files differ
diff --git a/doc/images/qtcreator-new-qt-quick-project-wizard.png b/doc/images/qtcreator-new-qt-quick-project-wizard.png
index 259e2fd83e..5a676cd42d 100644
--- a/doc/images/qtcreator-new-qt-quick-project-wizard.png
+++ b/doc/images/qtcreator-new-qt-quick-project-wizard.png
Binary files differ
diff --git a/doc/src/editors/creator-editors.qdoc b/doc/src/editors/creator-editors.qdoc
index 124be5bb69..22e93118fb 100644
--- a/doc/src/editors/creator-editors.qdoc
+++ b/doc/src/editors/creator-editors.qdoc
@@ -1466,6 +1466,11 @@
\endlist
+ The locations of search hits, breakpoints, and bookmarks in your document
+ are highlighted on the editor scroll bar. To turn highlighting off, select
+ \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} >
+ \uicontrol {Highlight search results on the scrollbar}.
+
\section1 Advanced Search
To search through projects, files on a file system or currently open files:
@@ -2403,9 +2408,10 @@
\endlist
- To move directly to a particular line in the document when you open the
- document, append a plus sign (+) or a colon (:) to the file name in the
- locator. For example, to open main.cpp to line 41, enter: \c {main.cpp:41}.
+ To move directly to a particular line and column in the document when you
+ open the document, append them to the file name in the locator, separated by
+ plus signs (+) or colons (:). For example, to open main.cpp to line 41 and
+ column 2, enter: \c {main.cpp:41:2}.
If the path to a file is very long, it might not fit into the locator
window. To view the full path, press \key Alt when the filename is selected
@@ -2446,7 +2452,7 @@
\li Locating symbols in the current document (\c {.})
\li Locating a specific line and column in the document displayed in
- your editor (\c {l})
+ your editor (\c {l <line_number>:<column_number>})
\li Opening help topics, including Qt documentation (\c {?})
@@ -2460,6 +2466,8 @@
\li Executing version control system commands (\c {git}). For more
information, see \l{Using Version Control Systems}
+ \li Running external tools (\c x)
+
\endlist
To use a specific locator filter, type the assigned prefix followed by
diff --git a/doc/src/howto/creator-cli.qdoc b/doc/src/howto/creator-cli.qdoc
index 194d29f0fe..392621642f 100644
--- a/doc/src/howto/creator-cli.qdoc
+++ b/doc/src/howto/creator-cli.qdoc
@@ -31,16 +31,16 @@
\title Using Command Line Options
You can start \QC and specify some options from the command line. For
- example, you can open a file to any line.
+ example, you can open a file to any line and column.
To specify command line options, enter the following command in the \QC
installation or build directory:
- \c {qtcreator [option] [filename[:line_number]]}
+ \c {qtcreator [option] [filename[:line_number[:column_number]]]}
\note You can use either a colon (:) or a plus sign (+) as a separator
- between the filename and line number. You can also use a space between the
- separator and the line number.
+ between the filename and line number and the line number and the column
+ number. You can also use a space between the separator and the line number.
For example, on Windows:
@@ -48,9 +48,9 @@
\li \c {C:\qtcreator\bin>qtcreator -help}
- \li \c {C:\qtcreator\bin>qtcreator C:\TextFinder\textfinder.cpp:100}
+ \li \c {C:\qtcreator\bin>qtcreator C:\TextFinder\textfinder.cpp:100:2}
- \li \c {C:\qtcreator\bin>qtcreator C:\TextFinder\textfinder.cpp +100}
+ \li \c {C:\qtcreator\bin>qtcreator C:\TextFinder\textfinder.cpp +100+2}
\endlist
diff --git a/doc/src/howto/creator-external-tools.qdoc b/doc/src/howto/creator-external-tools.qdoc
index c507749c3f..67bf9c2276 100644
--- a/doc/src/howto/creator-external-tools.qdoc
+++ b/doc/src/howto/creator-external-tools.qdoc
@@ -36,6 +36,9 @@
for use. You can change their default configurations and configure new
tools.
+ To run the tools, select \uicontrol Tools > \uicontrol External, or use the
+ \c x filter in the locator.
+
\section1 Using Qt Linguist
You can use the Qt Linguist release manager tools, lupdate and lrelease,
diff --git a/doc/src/howto/creator-keyboard-shortcuts.qdoc b/doc/src/howto/creator-keyboard-shortcuts.qdoc
index aae209af9c..8c2a0323b9 100644
--- a/doc/src/howto/creator-keyboard-shortcuts.qdoc
+++ b/doc/src/howto/creator-keyboard-shortcuts.qdoc
@@ -64,8 +64,19 @@
\li Select a command from the list.
- \li In \uicontrol{Key Sequence} enter the shortcut key you want to associate
- with the selected command.
+ \li In the \uicontrol{Key Sequence} field, you have the following
+ options:
+
+ \list
+
+ \li Enter the shortcut key you want to associate with the
+ selected command.
+
+ \li Select \uicontrol Record, press the keys to use as the
+ keyboard shortcut, and select \uicontrol {Stop Recording}
+ when you are done.
+
+ \endlist
\li To revert to the default shortcut, select \uicontrol Reset.
diff --git a/doc/src/projects/creator-projects-creating.qdoc b/doc/src/projects/creator-projects-creating.qdoc
index 2d9b680330..bc343c836b 100644
--- a/doc/src/projects/creator-projects-creating.qdoc
+++ b/doc/src/projects/creator-projects-creating.qdoc
@@ -114,6 +114,12 @@
Create a Qt Quick application using Qt Quick Controls
+ \li Qt Canvas 3D Application
+
+ Create a Qt Quick application that imports the Qt Canvas 3D
+ module and, optionally, includes \l{http://threejs.org}
+ {three.js}.
+
\li Qt Console Application
Use a single main.cpp file
diff --git a/doc/src/qtquick/qtquick-creating.qdoc b/doc/src/qtquick/qtquick-creating.qdoc
index 4e20650988..ea861f5b18 100644
--- a/doc/src/qtquick/qtquick-creating.qdoc
+++ b/doc/src/qtquick/qtquick-creating.qdoc
@@ -46,6 +46,10 @@
\li \uicontrol {Qt Quick Controls Application} is like
\uicontrol {Qt Quick Application}, but using Qt Quick Controls.
+ \li \uicontrol {Qt Canvas 3D Application} creates a Qt Quick application
+ that imports the Qt Canvas 3D module and, optionally, includes
+ \l{http://threejs.org}{three.js}.
+
\li \uicontrol {Qt Quick UI} (in the \uicontrol {Other Project}
category) creates a Qt Quick UI project with a single QML file that
contains the main view. You can review Qt Quick UI projects in a
diff --git a/qtcreator.pri b/qtcreator.pri
index f68fa435d5..71e7d4477e 100644
--- a/qtcreator.pri
+++ b/qtcreator.pri
@@ -1,9 +1,9 @@
!isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included")
QTCREATOR_PRI_INCLUDED = 1
-QTCREATOR_VERSION = 3.4.81
-QTCREATOR_COMPAT_VERSION = 3.4.81
-BINARY_ARTIFACTS_BRANCH = master
+QTCREATOR_VERSION = 3.4.82
+QTCREATOR_COMPAT_VERSION = 3.4.82
+BINARY_ARTIFACTS_BRANCH = 3.5
# enable c++11
CONFIG += c++11
diff --git a/qtcreator.qbs b/qtcreator.qbs
index b2dd649476..e9295856bb 100644
--- a/qtcreator.qbs
+++ b/qtcreator.qbs
@@ -6,11 +6,11 @@ Project {
property bool withAutotests: qbs.buildVariant === "debug"
property string ide_version_major: '3'
property string ide_version_minor: '4'
- property string ide_version_release: '81'
+ property string ide_version_release: '82'
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release
property string ide_compat_version_major: '3'
property string ide_compat_version_minor: '4'
- property string ide_compat_version_release: '81'
+ property string ide_compat_version_release: '82'
property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release
property path ide_source_tree: path
property string ide_app_path: qbs.targetOS.contains("osx") ? "" : "bin"
diff --git a/scripts/deployqt.py b/scripts/deployqt.py
index 23d2074785..00b70d1af4 100755
--- a/scripts/deployqt.py
+++ b/scripts/deployqt.py
@@ -191,7 +191,9 @@ def copy_qt_libs(install_dir, qt_libs_dir, qt_plugin_dir, qt_import_dir, qt_qml_
target = os.path.join(install_dir, 'bin', 'imports', qtimport)
if (os.path.exists(target)):
shutil.rmtree(target)
- shutil.copytree(os.path.join(qt_import_dir, qtimport), target, ignore=copy_ignore_func, symlinks=True)
+ import_path = os.path.join(qt_import_dir, qtimport)
+ if os.path.exists(import_path):
+ shutil.copytree(import_path, target, ignore=copy_ignore_func, symlinks=True)
if (os.path.exists(qt_qml_dir)):
print "Copying qt quick 2 imports"
@@ -230,20 +232,33 @@ def copyPreservingLinks(source, destination):
shutil.copy(source, destination)
def copy_libclang(install_dir, llvm_install_dir):
- libsources = []
- libtarget = ""
+ # contains pairs of (source, target directory)
+ deployinfo = []
if sys.platform.startswith("win"):
- libsources = [os.path.join(llvm_install_dir, 'bin', 'libclang.dll')]
- libtarget = os.path.join(install_dir, 'bin')
+ deployinfo.append((os.path.join(llvm_install_dir, 'bin', 'libclang.dll'),
+ os.path.join(install_dir, 'bin')))
+ deployinfo.append((os.path.join(llvm_install_dir, 'bin', 'clang-cl.exe'),
+ os.path.join(install_dir, 'bin')))
else:
libsources = glob(os.path.join(llvm_install_dir, 'lib', 'libclang.so*'))
- libtarget = os.path.join(install_dir, 'lib', 'qtcreator')
+ for libsource in libsources:
+ deployinfo.append((libsource, os.path.join(install_dir, 'lib', 'qtcreator')))
+ clangbinary = os.path.join(llvm_install_dir, 'bin', 'clang')
+ clangbinary_targetdir = os.path.join(install_dir, 'bin')
+ deployinfo.append((clangbinary, clangbinary_targetdir))
+ # copy link target if clang is actually a symlink
+ if os.path.islink(clangbinary):
+ linktarget = os.readlink(clangbinary)
+ deployinfo.append((os.path.join(os.path.dirname(clangbinary), linktarget),
+ os.path.join(clangbinary_targetdir, linktarget)))
+
resourcesource = os.path.join(llvm_install_dir, 'lib', 'clang')
resourcetarget = os.path.join(install_dir, 'share', 'qtcreator', 'cplusplus', 'clang')
+
print "copying libclang..."
- for libsource in libsources:
- print libsource, '->', libtarget
- copyPreservingLinks(libsource, libtarget)
+ for source, target in deployinfo:
+ print source, '->', target
+ copyPreservingLinks(source, target)
print resourcesource, '->', resourcetarget
if (os.path.exists(resourcetarget)):
shutil.rmtree(resourcetarget)
diff --git a/scripts/deployqtHelper_mac.sh b/scripts/deployqtHelper_mac.sh
index 120a4d030a..be7929a5ff 100755
--- a/scripts/deployqtHelper_mac.sh
+++ b/scripts/deployqtHelper_mac.sh
@@ -61,6 +61,12 @@ if [ $LLVM_INSTALL_DIR ]; then
# use recursive copy to make it copy symlinks as symlinks
cp -Rf "$LLVM_INSTALL_DIR"/lib/libclang.*dylib "$1/Contents/Frameworks/" || exit 1
cp -Rf "$LLVM_INSTALL_DIR"/lib/clang "$1/Contents/Resources/cplusplus/" || exit 1
+ clangsource="$LLVM_INSTALL_DIR"/bin/clang
+ clanglinktarget="$(readlink "$clangsource")"
+ cp -Rf "$clangsource" "$1/Contents/Resources/" || exit 1
+ if [ $clanglinktarget ]; then
+ cp -Rf "$(dirname "$clangsource")/$clanglinktarget" "$1/Contents/Resources/$clanglinktarget" || exit 1
+ fi
fi
_CLANG_CODEMODEL_LIB="$1/Contents/PlugIns/libClangCodeModel_debug.dylib"
if [ ! -f "$_CLANG_CODEMODEL_LIB" ]; then
diff --git a/scripts/unixdeployqt.sh b/scripts/unixdeployqt.sh
deleted file mode 100755
index be843f3e30..0000000000
--- a/scripts/unixdeployqt.sh
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/bin/bash
-################################################################################
-# Copyright (C) 2015 The Qt Company Ltd
-# All rights reserved.
-#
-# 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 Qt Company Ltd, 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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
-################################################################################
-
-if [ $# -lt 1 ]; then
- echo "Usage: $(basename $1) <creator_install_dir> [qmake_path]"
- exit 1
-fi
-
-INSTALL_DIR="$1"
-QMAKE_BIN="${2:-$(which qmake)}"
-
-if [ ! -e "$QMAKE_BIN" ]; then
- echo "Could not detetermine location of 'qmake'!"
- exit 1;
-fi
-
-CHRPATH=$(which chrpath)
-if [ ! -e "$CHRPATH" ]; then
- echo "Cannot find required binary 'chrpath'."
- exit 1
-fi
-
-QT_INSTALL_LIBS="$($QMAKE_BIN -query QT_INSTALL_LIBS)"
-QT_INSTALL_PLUGINS="$($QMAKE_BIN -query QT_INSTALL_PLUGINS)"
-QT_INSTALL_IMPORTS="$($QMAKE_BIN -query QT_INSTALL_IMPORTS)"
-QT_INSTALL_TRANSLATIONS="$($QMAKE_BIN -query QT_INSTALL_TRANSLATIONS)"
-
-plugins="accessible designer iconengines imageformats sqldrivers"
-imports="Qt QtWebKit"
-tr_catalogs="assistant designer qt qt_help"
-tr_languages="$(cd $INSTALL_DIR/share/qtcreator/translations; echo qtcreator_* | sed -e 's,[^_]*_\([^.]*\)\.,\1 ,g')"
-
-function fix_rpaths()
-{
- pushd $INSTALL_DIR/lib
- find qtcreator/ -maxdepth 1 -name "*.so*" -type f -exec $CHRPATH -r \$ORIGIN {} \;
- cd $INSTALL_DIR/lib/qtcreator
- find plugins/ -maxdepth 2 -name "*.so" -type f -exec $CHRPATH -r \$ORIGIN/../.. {} \;
-
- cd $INSTALL_DIR/bin
- # all executable files in bin
- find -maxdepth 1 -type f -executable -exec $CHRPATH -r \$ORIGIN/../lib/qtcreator {} \;
- # all lib of imports and plugins one level underneath bin
- find -mindepth 2 -maxdepth 2 -type f -name "*.so" -exec $CHRPATH -r \$ORIGIN/../../lib/qtcreator {} \;
- find -mindepth 3 -maxdepth 3 -type f -name "*.so" -exec $CHRPATH -r \$ORIGIN/../../../lib/qtcreator {} \;
- find -mindepth 4 -maxdepth 4 -type f -name "*.so" -exec $CHRPATH -r \$ORIGIN/../../../../lib/qtcreator {} \;
-}
-
-function copy_binaries()
-{
- cp -a $QT_INSTALL_LIBS/*.so* $INSTALL_DIR/lib/qtcreator
-
- for plugin in $plugins; do
- cp -a $QT_INSTALL_PLUGINS/$plugin $INSTALL_DIR/bin
- done
-
- for import in $imports; do
- cp -a $QT_INSTALL_IMPORTS/$import $INSTALL_DIR/bin
- done
-}
-
-function copy_translations()
-{
- for language in $tr_languages; do
- for catalog in $tr_catalogs; do
- cp -a $QT_INSTALL_TRANSLATIONS/${catalog}_${language}.qm $INSTALL_DIR/share/qtcreator/translations
- done
- done
-}
-
-copy_binaries
-copy_translations
-fix_rpaths
-
diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py
index 28c2c4c2e0..16682a47c7 100644
--- a/share/qtcreator/debugger/dumper.py
+++ b/share/qtcreator/debugger/dumper.py
@@ -387,12 +387,27 @@ class DumperBase:
self.isCli = False
# Later set, or not set:
- # cachedQtVersion
self.stringCutOff = 10000
self.displayStringLimit = 100
+ self.resetCaches()
+
+ self.childrenPrefix = 'children=['
+ self.childrenSuffix = '],'
+
+ self.dumpermodules = [
+ "qttypes",
+ "stdtypes",
+ "misctypes",
+ "boosttypes",
+ "creatortypes",
+ "personaltypes",
+ ]
+
+
+ def resetCaches(self):
# This is a cache mapping from 'type name' to 'display alternatives'.
- self.qqFormats = {}
+ self.qqFormats = { "QVariant (QVariantMap)" : mapForms() }
# This is a cache of all known dumpers.
self.qqDumpers = {}
@@ -407,18 +422,6 @@ class DumperBase:
# to not be QObject derived, it contains a 0 value.
self.knownStaticMetaObjects = {}
- self.childrenPrefix = 'children=['
- self.childrenSuffix = '],'
-
- self.dumpermodules = [
- "qttypes",
- "stdtypes",
- "misctypes",
- "boosttypes",
- "creatortypes",
- "personaltypes",
- ]
-
def putNewline(self):
pass
@@ -1674,10 +1677,7 @@ class DumperBase:
pass
def setupDumpers(self, _ = {}):
- self.qqDumpers = {}
- self.qqFormats = {}
- self.qqEditable = {}
- self.typeCache = {}
+ self.resetCaches()
for mod in self.dumpermodules:
m = importlib.import_module(mod)
diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py
index 95d3c1f26d..088a618b0c 100644
--- a/share/qtcreator/debugger/gdbbridge.py
+++ b/share/qtcreator/debugger/gdbbridge.py
@@ -144,6 +144,7 @@ ScanStackCommand()
class PlainDumper:
def __init__(self, printer):
self.printer = printer
+ self.typeCache = {}
def __call__(self, d, value):
printer = self.printer.invoke(value)
@@ -223,6 +224,7 @@ class Dumper(DumperBase):
# These values will be kept between calls to 'showData'.
self.isGdb = True
self.childEventAddress = None
+ self.typeCache = {}
self.typesReported = {}
self.typesToReport = {}
self.qtNamespaceToReport = None
diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py
index 268da78f71..90a256f484 100644
--- a/share/qtcreator/debugger/qttypes.py
+++ b/share/qtcreator/debugger/qttypes.py
@@ -1031,6 +1031,13 @@ def qdump__QMultiMap(d, value):
qdump__QMap(d, value)
+def qform__QVariantMap():
+ return mapForms()
+
+def qdump__QVariantMap(d, value):
+ qdump__QMap(d, value)
+
+
def qdump__QMetaObjectPrivate(d, value):
d.putEmptyValue()
d.putNumChild(1)
@@ -1899,6 +1906,16 @@ def qdump__QUrl(d, value):
d.putGenericItem("fragment", stringType, fragment, Hex4EncodedLittleEndian)
d.putFields(value)
+
+def qdump__QUuid(d, value):
+ v = value["data4"]
+ d.putValue("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"
+ % (value["data1"], value["data2"], value["data3"],
+ v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]))
+ d.putNumChild(1)
+ d.putPlainChildren(value)
+
+
def qdumpHelper_QVariant_0(d, blob):
# QVariant::Invalid
d.putBetterType("%sQVariant (invalid)" % d.qtNamespace())
diff --git a/share/qtcreator/static.pro b/share/qtcreator/static.pro
index 4e0c6b8400..37a44a1aa6 100644
--- a/share/qtcreator/static.pro
+++ b/share/qtcreator/static.pro
@@ -72,12 +72,6 @@ for(data_dir, DATA_DIRS) {
dumpinfo.input = qml/qmldump/Info.plist.in
dumpinfo.output = $$IDE_DATA_PATH/qml/qmldump/Info.plist
QMAKE_SUBSTITUTES += dumpinfo
- puppetinfo.input = qml/qmlpuppet/qmlpuppet/Info.plist.in
- puppetinfo.output = $$IDE_DATA_PATH/qml/qmlpuppet/qmlpuppet/Info.plist
- QMAKE_SUBSTITUES += puppetinfo
- puppet2info.input = qml/qmlpuppet/qml2puppet/Info.plist.in
- puppet2info.output = $$IDE_DATA_PATH/qml/qmlpuppet/qml2puppet/Info.plist
- QMAKE_SUBSTITUES += puppet2info
}
SRCRESOURCEDIR = $$IDE_SOURCE_TREE/src/share/qtcreator/
diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json
index d633eddf6b..ff84948f89 100644
--- a/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json
@@ -7,8 +7,8 @@
"trDisplayName": "Qt Quick Application",
"trDisplayCategory": "Application",
"icon": "qml_wizard.png",
- "featuresRequired": [ "QtSupport.Wizards.FeatureQt", "QtSupport.Wizards.FeatureQtQuick.2" ],
- "enabled": "${JS: [ %{Plugins} ].indexOf('QmakeProjectManager') >= 0 && [ %{Features} ].indexOf('QtSupport.Wizards.FeatureQt5.3') >= 0}",
+ "featuresRequired": [ "QtSupport.Wizards.FeatureQt.5.3" ],
+ "enabled": "%{JS: [ %{Plugins} ].indexOf('QmakeProjectManager') >= 0 }",
"options":
[
@@ -38,6 +38,7 @@
"type": "ComboBox",
"data":
{
+ "index": 2,
"items":
[
{
@@ -46,8 +47,7 @@
"{
'qtQuickVersion': '2.5',
'qtQuickWindowVersion': '2.2'
- }",
- "condition": "%{JS: [ %{Features} ].indexOf('QtSupport.Wizards.FeatureQt5.5') >= 0}"
+ }"
},
{
"trKey": "Qt 5.4",
@@ -55,8 +55,7 @@
"{
'qtQuickVersion': '2.4',
'qtQuickWindowVersion': '2.2'
- }",
- "condition": "%{JS: [ %{Features} ].indexOf('QtSupport.Wizards.FeatureQt5.4') >= 0}"
+ }"
},
{
"trKey": "Qt 5.3",
@@ -64,8 +63,7 @@
"{
'qtQuickVersion': '2.3',
'qtQuickWindowVersion': '2.2'
- }",
- "condition": "%{JS: [ %{Features} ].indexOf('QtSupport.Wizards.FeatureQt5.3') >= 0}"
+ }"
}
]
}
diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json
index 7738f28e5a..0a57e21bf3 100644
--- a/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json
@@ -7,8 +7,8 @@
"trDisplayName": "Qt Quick Controls Application",
"trDisplayCategory": "Application",
"icon": "../qtquickapplication/qml_wizard.png",
- "featuresRequired": [ "QtSupport.Wizards.FeatureQt" ],
- "enabled": "%{JS: [ %{Plugins} ].indexOf('QmakeProjectManager') >= 0 && [ %{Features} ].indexOf('QtSupport.Wizards.FeatureQt5.3') >= 0 }",
+ "featuresRequired": [ "QtSupport.Wizards.FeatureQt.5.3" ],
+ "enabled": "%{JS: [ %{Plugins} ].indexOf('QmakeProjectManager') >= 0}",
"options":
[
@@ -40,6 +40,7 @@
"type": "ComboBox",
"data":
{
+ "index": 2,
"items":
[
{
@@ -50,8 +51,7 @@
'qtQuickControlsVersion': '1.4',
'qtQuickDialogsVersion': '1.2',
'qtQuickLayoutsVersion': '1.2'
- }",
- "condition": "%{JS: [ %{Features} ].indexOf('QtSupport.Wizards.FeatureQt5.5') >= 0}"
+ }"
},
{
"trKey": "Qt 5.4",
@@ -61,8 +61,7 @@
'qtQuickControlsVersion': '1.3',
'qtQuickDialogsVersion': '1.2',
'qtQuickLayoutsVersion': '1.1'
- }",
- "condition": "%{JS: [ %{Features} ].indexOf('QtSupport.Wizards.FeatureQt5.4') >= 0}"
+ }"
},
{
"trKey": "Qt 5.3",
@@ -72,8 +71,7 @@
'qtQuickControlsVersion': '1.2',
'qtQuickDialogsVersion': '1.2',
'qtQuickLayoutsVersion': '1.1'
- }",
- "condition": "%{JS: [ %{Features} ].indexOf('QtSupport.Wizards.FeatureQt5.3') >= 0}"
+ }"
}
]
}
diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
index 64053b4a5b..5af16f3e4f 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
+++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
@@ -164,8 +164,8 @@ void AutotoolsProject::loadProjectTree()
// The thread is still busy parsing a previus configuration.
// Wait until the thread has been finished and delete it.
// TODO: Discuss whether blocking is acceptable.
- disconnect(m_makefileParserThread, SIGNAL(finished()),
- this, SLOT(makefileParsingFinished()));
+ disconnect(m_makefileParserThread, &QThread::finished,
+ this, &AutotoolsProject::makefileParsingFinished);
m_makefileParserThread->wait();
delete m_makefileParserThread;
m_makefileParserThread = 0;
@@ -402,6 +402,24 @@ QList<Node *> AutotoolsProject::nodes(FolderNode *parent) const
return list;
}
+static QStringList filterIncludes(const QString &absSrc, const QString &absBuild,
+ const QStringList &in)
+{
+ QStringList result;
+ foreach (const QString i, in) {
+ QString out = i;
+ out.replace(QLatin1String("$(top_srcdir)"), absSrc);
+ out.replace(QLatin1String("$(abs_top_srcdir)"), absSrc);
+
+ out.replace(QLatin1String("$(top_builddir)"), absBuild);
+ out.replace(QLatin1String("$(abs_top_builddir)"), absBuild);
+
+ result << out;
+ }
+
+ return result;
+}
+
void AutotoolsProject::updateCppCodeModel()
{
CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
@@ -427,7 +445,12 @@ void AutotoolsProject::updateCppCodeModel()
ppBuilder.setCFlags(cflags);
ppBuilder.setCxxFlags(cxxflags);
- ppBuilder.setIncludePaths(m_makefileParserThread->includePaths());
+ const QString absSrc = projectDirectory().toString();
+ const Target *target = activeTarget();
+ const QString absBuild = (target && target->activeBuildConfiguration())
+ ? target->activeBuildConfiguration()->buildDirectory().toString() : QString();
+
+ ppBuilder.setIncludePaths(filterIncludes(absSrc, absBuild, m_makefileParserThread->includePaths()));
ppBuilder.setDefines(m_makefileParserThread->defines());
const QList<Core::Id> languages = ppBuilder.createProjectPartsForFiles(m_files);
diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.cpp b/src/plugins/autotoolsprojectmanager/makefileparser.cpp
index 3c1e94d133..48436899eb 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparser.cpp
+++ b/src/plugins/autotoolsprojectmanager/makefileparser.cpp
@@ -33,6 +33,7 @@
#include "makefileparser.h"
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <QFile>
#include <QDir>
@@ -131,12 +132,12 @@ QByteArray MakefileParser::defines() const
QStringList MakefileParser::cflags() const
{
- return m_cflags;
+ return m_cppflags + m_cflags;
}
QStringList MakefileParser::cxxflags() const
{
- return m_cxxflags;
+ return m_cppflags + m_cxxflags;
}
void MakefileParser::cancel()
@@ -443,9 +444,22 @@ QString MakefileParser::parseIdentifierBeforeAssign(const QString &line)
QStringList MakefileParser::parseTermsAfterAssign(const QString &line)
{
int assignPos = line.indexOf(QLatin1Char('=')) + 1;
- if (assignPos >= line.size())
+ if (assignPos <= 0 || assignPos >= line.size())
return QStringList();
- return line.mid(assignPos).split(QLatin1Char(' '), QString::SkipEmptyParts);
+
+ const QStringList parts = Utils::QtcProcess::splitArgs(line.mid(assignPos));
+ QStringList result;
+ for (int i = 0; i < parts.count(); ++i) {
+ const QString cur = parts.at(i);
+ const QString next = (i == parts.count() - 1) ? QString() : parts.at(i + 1);
+ if (cur == QLatin1String("-D") || cur == QLatin1String("-U") || cur == QLatin1String("-I")) {
+ result << cur + next;
+ ++i;
+ } else {
+ result << cur;
+ }
+ }
+ return result;
}
bool MakefileParser::maybeParseDefine(const QString &term)
@@ -493,6 +507,15 @@ bool MakefileParser::maybeParseCXXFlag(const QString &term)
return false;
}
+bool MakefileParser::maybeParseCPPFlag(const QString &term)
+{
+ if (term.startsWith(QLatin1Char('-'))) {
+ m_cppflags += term;
+ return true;
+ }
+ return false;
+}
+
void MakefileParser::addAllSources()
{
QStringList extensions;
@@ -523,6 +546,12 @@ void MakefileParser::parseIncludePaths()
QString line;
do {
line = textStream.readLine();
+ while (line.endsWith(QLatin1Char('\\'))) {
+ line.chop(1);
+ QString next = textStream.readLine();
+ line.append(next);
+ }
+
const QString varName = parseIdentifierBeforeAssign(line);
if (varName.isEmpty())
continue;
@@ -537,11 +566,14 @@ void MakefileParser::parseIncludePaths()
foreach (const QString &term, parseTermsAfterAssign(line))
maybeParseDefine(term) || maybeParseInclude(term, dirName)
|| maybeParseCFlag(term);
- } else if (varName.endsWith(QLatin1String("CPPFLAGS"))
- || varName.endsWith(QLatin1String("CXXFLAGS"))) {
+ } else if (varName.endsWith(QLatin1String("CXXFLAGS"))) {
foreach (const QString &term, parseTermsAfterAssign(line))
maybeParseDefine(term) || maybeParseInclude(term, dirName)
|| maybeParseCXXFlag(term);
+ } else if (varName.endsWith(QLatin1String("CPPFLAGS"))) {
+ foreach (const QString &term, parseTermsAfterAssign(line))
+ maybeParseDefine(term) || maybeParseInclude(term, dirName)
+ || maybeParseCPPFlag(term);
}
} while (!line.isNull());
diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.h b/src/plugins/autotoolsprojectmanager/makefileparser.h
index 463c56e65a..32569d6a11 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparser.h
+++ b/src/plugins/autotoolsprojectmanager/makefileparser.h
@@ -258,6 +258,11 @@ private:
*/
bool maybeParseCXXFlag(const QString &term);
+ /**
+ * If term is compiler flag -<flag>, adds it to cppflags and returns true.
+ */
+ bool maybeParseCPPFlag(const QString &term);
+
private:
bool m_success; ///< Return value for MakefileParser::parse().
@@ -271,7 +276,8 @@ private:
QStringList m_includePaths; ///< Return value for MakefileParser::includePaths()
QByteArray m_defines; ///< Return value for MakefileParser::defines()
QStringList m_cflags; ///< Return value for MakefileParser::cflags()
- QStringList m_cxxflags; ///< Return value for MakefileParser::cxxflags()
+ QStringList m_cxxflags; ///< Return value for MakefileParser::cxxflags()
+ QStringList m_cppflags; ///< The cpp flags, which will be part of both cflags and cxxflags
QString m_line; ///< Current line of the makefile
QTextStream m_textStream; ///< Textstream that represents the makefile
diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.h b/src/plugins/clangcodemodel/clangeditordocumentparser.h
index cbdce90f2d..e86cf50f94 100644
--- a/src/plugins/clangcodemodel/clangeditordocumentparser.h
+++ b/src/plugins/clangcodemodel/clangeditordocumentparser.h
@@ -28,7 +28,6 @@
**
****************************************************************************/
-
#ifndef CLANGEDITORDOCUMENTPARSER_H
#define CLANGEDITORDOCUMENTPARSER_H
@@ -36,7 +35,6 @@
#include <cpptools/baseeditordocumentparser.h>
-
namespace CppTools { class WorkingCopy; }
namespace ClangCodeModel {
@@ -46,9 +44,6 @@ class ClangEditorDocumentParser : public CppTools::BaseEditorDocumentParser
Q_OBJECT
public:
- typedef QSharedPointer<ClangEditorDocumentParser> Ptr;
-
-public:
ClangEditorDocumentParser(const QString &filePath);
void update(CppTools::WorkingCopy workingCopy) override;
@@ -59,8 +54,6 @@ public:
private:
SemanticMarker::Ptr m_marker;
- QStringList m_options;
- Internal::UnsavedFiles m_unsavedFiles;
};
} // namespace ClangCodeModel
diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
index 36bd7aebfd..8115b52577 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
@@ -69,6 +69,10 @@ ModelManagerSupportClang::ModelManagerSupportClang()
this, &ModelManagerSupportClang::onEditorOpened);
CppTools::CppModelManager *modelManager = cppModelManager();
+ connect(modelManager, &CppTools::CppModelManager::abstractEditorSupportContentsUpdated,
+ this, &ModelManagerSupportClang::onAbstractEditorSupportContentsUpdated);
+ connect(modelManager, &CppTools::CppModelManager::abstractEditorSupportRemoved,
+ this, &ModelManagerSupportClang::onAbstractEditorSupportRemoved);
connect(modelManager, &CppTools::CppModelManager::projectPartsUpdated,
this, &ModelManagerSupportClang::onProjectPartsUpdated);
connect(modelManager, &CppTools::CppModelManager::projectPartsRemoved,
@@ -113,9 +117,8 @@ void ModelManagerSupportClang::onEditorOpened(Core::IEditor *editor)
Core::IDocument *document = editor->document();
QTC_ASSERT(document, return);
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(document);
- QTC_ASSERT(textDocument, return);
- if (cppModelManager()->isCppEditor(editor)) {
+ if (textDocument && cppModelManager()->isCppEditor(editor)) {
// Handle externally changed documents
connect(textDocument, &Core::IDocument::reloadFinished,
this, &ModelManagerSupportClang::onCppDocumentReloadFinished,
diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
index 58de825850..95c43eeb20 100644
--- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
+++ b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
@@ -615,6 +615,102 @@ bool hasSnippet(ProposalModel model, const QByteArray &text)
return false;
}
+class MonitorGeneratedUiFile : public QObject
+{
+ Q_OBJECT
+
+public:
+ MonitorGeneratedUiFile();
+ bool waitUntilGenerated(int timeout = 10000) const;
+
+private:
+ void onUiFileGenerated() { m_isGenerated = true; }
+
+ bool m_isGenerated = false;
+};
+
+MonitorGeneratedUiFile::MonitorGeneratedUiFile()
+{
+ connect(CppTools::CppModelManager::instance(),
+ &CppTools::CppModelManager::abstractEditorSupportContentsUpdated,
+ this, &MonitorGeneratedUiFile::onUiFileGenerated);
+}
+
+bool MonitorGeneratedUiFile::waitUntilGenerated(int timeout) const
+{
+ if (m_isGenerated)
+ return true;
+
+ QTime time;
+ time.start();
+
+ forever {
+ if (m_isGenerated)
+ return true;
+
+ if (time.elapsed() > timeout)
+ return false;
+
+ QCoreApplication::processEvents();
+ QThread::msleep(20);
+ }
+
+ return false;
+}
+
+class WriteFileAndWaitForReloadedDocument : public QObject
+{
+public:
+ WriteFileAndWaitForReloadedDocument(const QString &filePath,
+ const QByteArray &fileContents,
+ Core::IDocument *document)
+ : m_filePath(filePath)
+ , m_fileContents(fileContents)
+ {
+ QTC_CHECK(document);
+ connect(document, &Core::IDocument::reloadFinished,
+ this, &WriteFileAndWaitForReloadedDocument::onReloadFinished);
+ }
+
+ void onReloadFinished()
+ {
+ m_onReloadFinished = true;
+ }
+
+ bool wait() const
+ {
+ QTC_ASSERT(writeFile(m_filePath, m_fileContents), return false);
+
+ QTime totalTime;
+ totalTime.start();
+
+ QTime writeFileAgainTime;
+ writeFileAgainTime.start();
+
+ forever {
+ if (m_onReloadFinished)
+ return true;
+
+ if (totalTime.elapsed() > 10000)
+ return false;
+
+ if (writeFileAgainTime.elapsed() > 1000) {
+ // The timestamp did not change, try again now.
+ QTC_ASSERT(writeFile(m_filePath, m_fileContents), return false);
+ writeFileAgainTime.restart();
+ }
+
+ QCoreApplication::processEvents();
+ QThread::msleep(20);
+ }
+ }
+
+private:
+ bool m_onReloadFinished = false;
+ QString m_filePath;
+ QByteArray m_fileContents;
+};
+
} // anonymous namespace
namespace ClangCodeModel {
@@ -866,11 +962,11 @@ void ClangCodeCompletionTest::testUnsavedFilesTrackingByModifyingIncludedFileExt
ProposalModel proposal = completionResults(openSource.editor());
QVERIFY(hasItem(proposal, "globalFromHeader"));
- // Simulate external modification
- QThread::sleep(1); // Ensures different time stamp and thus that the difference will be noticed
- QVERIFY(writeFile(headerDocument.filePath, "int globalFromHeaderReloaded;\n"));
- QSignalSpy waitForReloadedDocument(openHeader.editor()->document(),
- SIGNAL(reloadFinished(bool)));
+ // Simulate external modification and wait for reload
+ WriteFileAndWaitForReloadedDocument waitForReloadedDocument(
+ headerDocument.filePath,
+ "int globalFromHeaderReloaded;\n",
+ openHeader.editor()->document());
QVERIFY(waitForReloadedDocument.wait());
// Retrigger completion and check if its updated
@@ -883,6 +979,8 @@ void ClangCodeCompletionTest::testUnsavedFilesTrackingByCompletingUiObject()
CppTools::Tests::TemporaryCopiedDir testDir(qrcPath("qt-widgets-app"));
QVERIFY(testDir.isValid());
+ MonitorGeneratedUiFile monitorGeneratedUiFile;
+
// Open project
const QString projectFilePath = testDir.absolutePath("qt-widgets-app.pro");
CppTools::Tests::ProjectOpenerAndCloser projectManager;
@@ -897,11 +995,11 @@ void ClangCodeCompletionTest::testUnsavedFilesTrackingByCompletingUiObject()
QVERIFY(openSource.succeeded());
// ...and check comletions
+ QVERIFY(monitorGeneratedUiFile.waitUntilGenerated());
ProposalModel proposal = completionResults(openSource.editor());
QVERIFY(hasItem(proposal, "menuBar"));
QVERIFY(hasItem(proposal, "statusBar"));
QVERIFY(hasItem(proposal, "centralWidget"));
- QEXPECT_FAIL("", "Signals are not yet done", Abort);
QVERIFY(hasItem(proposal, "setupUi"));
}
@@ -921,6 +1019,7 @@ void ClangCodeCompletionTest::testUpdateBackendAfterRestart()
// ... and modify it, so we have an unsaved file.
insertTextAtTopOfEditor(openHeader.editor(), "int someGlobal;\n");
// Open project ...
+ MonitorGeneratedUiFile monitorGeneratedUiFile;
const QString projectFilePath = testDir.absolutePath("qt-widgets-app.pro");
CppTools::Tests::ProjectOpenerAndCloser projectManager;
const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
@@ -931,6 +1030,7 @@ void ClangCodeCompletionTest::testUpdateBackendAfterRestart()
QVERIFY(testDocument.isCreatedAndHasValidCursorPosition());
OpenEditorAtCursorPosition openSource(testDocument);
QVERIFY(openSource.succeeded());
+ QVERIFY(monitorGeneratedUiFile.waitUntilGenerated());
// Check commands that would have been sent
QVERIFY(compare(LogOutput(spy.senderLog),
@@ -939,6 +1039,8 @@ void ClangCodeCompletionTest::testUpdateBackendAfterRestart()
" ProjectPartContainer id: qt-widgets-app.pro\n"
"RegisterTranslationUnitForCodeCompletionCommand\n"
" Path: myheader.h ProjectPart: \n"
+ "RegisterTranslationUnitForCodeCompletionCommand\n"
+ " Path: ui_mainwindow.h ProjectPart: \n"
)));
spy.senderLog.clear();
@@ -966,3 +1068,5 @@ void ClangCodeCompletionTest::testUpdateBackendAfterRestart()
} // namespace Tests
} // namespace Internal
} // namespace ClangCodeModel
+
+#include "clangcodecompletion_test.moc"
diff --git a/src/plugins/cpptools/abstracteditorsupport.cpp b/src/plugins/cpptools/abstracteditorsupport.cpp
index e9f77f9e31..843ce0f06f 100644
--- a/src/plugins/cpptools/abstracteditorsupport.cpp
+++ b/src/plugins/cpptools/abstracteditorsupport.cpp
@@ -53,6 +53,11 @@ void AbstractEditorSupport::updateDocument()
m_modelmanager->updateSourceFiles(QSet<QString>() << fileName());
}
+void AbstractEditorSupport::notifyAboutUpdatedContents() const
+{
+ m_modelmanager->emitAbstractEditorSupportContentsUpdated(fileName(), contents());
+}
+
QString AbstractEditorSupport::licenseTemplate(const QString &file, const QString &className)
{
return Internal::CppFileSettings::licenseTemplate(file, className);
diff --git a/src/plugins/cpptools/abstracteditorsupport.h b/src/plugins/cpptools/abstracteditorsupport.h
index b1919fcff2..606fcca9a2 100644
--- a/src/plugins/cpptools/abstracteditorsupport.h
+++ b/src/plugins/cpptools/abstracteditorsupport.h
@@ -51,6 +51,7 @@ public:
virtual QString fileName() const = 0;
void updateDocument();
+ void notifyAboutUpdatedContents() const;
unsigned revision() const { return m_revision; }
static QString licenseTemplate(const QString &file = QString(), const QString &className = QString());
diff --git a/src/plugins/cpptools/baseeditordocumentparser.h b/src/plugins/cpptools/baseeditordocumentparser.h
index 544bc92e47..ddd12fbb0a 100644
--- a/src/plugins/cpptools/baseeditordocumentparser.h
+++ b/src/plugins/cpptools/baseeditordocumentparser.h
@@ -41,8 +41,6 @@ namespace CppTools {
class CPPTOOLS_EXPORT BaseEditorDocumentParser : public QObject
{
Q_OBJECT
- Q_DISABLE_COPY(BaseEditorDocumentParser)
- BaseEditorDocumentParser();
public:
BaseEditorDocumentParser(const QString &filePath);
diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.h b/src/plugins/cpptools/baseeditordocumentprocessor.h
index 8054d866e5..4f30a519e3 100644
--- a/src/plugins/cpptools/baseeditordocumentprocessor.h
+++ b/src/plugins/cpptools/baseeditordocumentprocessor.h
@@ -49,8 +49,6 @@ namespace CppTools {
class CPPTOOLS_EXPORT BaseEditorDocumentProcessor : public QObject
{
Q_OBJECT
- Q_DISABLE_COPY(BaseEditorDocumentProcessor)
- BaseEditorDocumentProcessor();
public:
BaseEditorDocumentProcessor(TextEditor::TextDocument *document);
diff --git a/src/plugins/cpptools/builtineditordocumentprocessor.h b/src/plugins/cpptools/builtineditordocumentprocessor.h
index 396ba1bf1a..b0db31e009 100644
--- a/src/plugins/cpptools/builtineditordocumentprocessor.h
+++ b/src/plugins/cpptools/builtineditordocumentprocessor.h
@@ -42,7 +42,6 @@ namespace CppTools {
class CPPTOOLS_EXPORT BuiltinEditorDocumentProcessor : public BaseEditorDocumentProcessor
{
Q_OBJECT
- BuiltinEditorDocumentProcessor();
public:
BuiltinEditorDocumentProcessor(TextEditor::TextDocument *document,
diff --git a/src/plugins/cpptools/cppeditoroutline.h b/src/plugins/cpptools/cppeditoroutline.h
index c40ef4327d..7017b44d9b 100644
--- a/src/plugins/cpptools/cppeditoroutline.h
+++ b/src/plugins/cpptools/cppeditoroutline.h
@@ -51,7 +51,6 @@ namespace CppTools {
class CPPTOOLS_EXPORT CppEditorOutline : public QObject
{
Q_OBJECT
- Q_DISABLE_COPY(CppEditorOutline)
public:
explicit CppEditorOutline(TextEditor::TextEditorWidget *editorWidget);
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
index 01132b9ebb..0d1b13621d 100644
--- a/src/plugins/cpptools/cppmodelmanager.cpp
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -958,6 +958,17 @@ void CppModelManager::emitDocumentUpdated(Document::Ptr doc)
emit documentUpdated(doc);
}
+void CppModelManager::emitAbstractEditorSupportContentsUpdated(const QString &filePath,
+ const QByteArray &contents)
+{
+ emit abstractEditorSupportContentsUpdated(filePath, contents);
+}
+
+void CppModelManager::emitAbstractEditorSupportRemoved(const QString &filePath)
+{
+ emit abstractEditorSupportRemoved(filePath);
+}
+
void CppModelManager::onProjectAdded(ProjectExplorer::Project *)
{
QMutexLocker locker(&d->m_projectMutex);
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
index 9a141ac8e3..24b2d2d6ee 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -111,6 +111,9 @@ public:
bool replaceDocument(Document::Ptr newDoc);
void emitDocumentUpdated(CPlusPlus::Document::Ptr doc);
+ void emitAbstractEditorSupportContentsUpdated(const QString &filePath,
+ const QByteArray &contents);
+ void emitAbstractEditorSupportRemoved(const QString &filePath);
bool isCppEditor(Core::IEditor *editor) const;
@@ -173,6 +176,9 @@ signals:
void gcFinished(); // Needed for tests.
+ void abstractEditorSupportContentsUpdated(const QString &filePath, const QByteArray &contents);
+ void abstractEditorSupportRemoved(const QString &filePath);
+
public slots:
void updateModifiedSourceFiles();
void GC();
diff --git a/src/plugins/cpptools/cppsemanticinfoupdater.h b/src/plugins/cpptools/cppsemanticinfoupdater.h
index 40eb7a2749..9b36254326 100644
--- a/src/plugins/cpptools/cppsemanticinfoupdater.h
+++ b/src/plugins/cpptools/cppsemanticinfoupdater.h
@@ -43,7 +43,6 @@ class SemanticInfoUpdaterPrivate;
class SemanticInfoUpdater : public QObject
{
Q_OBJECT
- Q_DISABLE_COPY(SemanticInfoUpdater)
public:
explicit SemanticInfoUpdater();
diff --git a/src/plugins/cpptools/semantichighlighter.h b/src/plugins/cpptools/semantichighlighter.h
index d00db6e9da..8485539e2e 100644
--- a/src/plugins/cpptools/semantichighlighter.h
+++ b/src/plugins/cpptools/semantichighlighter.h
@@ -49,7 +49,6 @@ namespace CppTools {
class CPPTOOLS_EXPORT SemanticHighlighter : public QObject
{
Q_OBJECT
- Q_DISABLE_COPY(SemanticHighlighter)
public:
enum Kind {
diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs
index 3322d95b83..f682cdc4b5 100644
--- a/src/plugins/debugger/debugger.qbs
+++ b/src/plugins/debugger/debugger.qbs
@@ -145,16 +145,13 @@ QtcPlugin {
name: "QML Debugger"
prefix: "qml/"
files: [
- "baseqmldebuggerclient.cpp", "baseqmldebuggerclient.h",
"interactiveinterpreter.cpp", "interactiveinterpreter.h",
- "qmladapter.cpp", "qmladapter.h",
"qmlcppengine.cpp", "qmlcppengine.h",
"qmlengine.cpp", "qmlengine.h",
+ "qmlengineutils.cpp", "qmlengineutils.h",
"qmlinspectoradapter.cpp", "qmlinspectoradapter.h",
"qmlinspectoragent.cpp", "qmlinspectoragent.h",
- "qmlv8debuggerclient.cpp", "qmlv8debuggerclient.h",
- "qmlv8debuggerclientconstants.h",
- "qscriptdebuggerclient.cpp", "qscriptdebuggerclient.h"
+ "qmlv8debuggerclientconstants.h"
]
}
diff --git a/src/plugins/debugger/qml/baseqmldebuggerclient.cpp b/src/plugins/debugger/qml/baseqmldebuggerclient.cpp
deleted file mode 100644
index 5a7f9287a1..0000000000
--- a/src/plugins/debugger/qml/baseqmldebuggerclient.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#include "baseqmldebuggerclient.h"
-#include <debugger/breakhandler.h>
-
-#include <utils/qtcassert.h>
-
-namespace Debugger {
-namespace Internal {
-
-class BaseQmlDebuggerClientPrivate
-{
-public:
- QList<QByteArray> sendBuffer;
-};
-
-BaseQmlDebuggerClient::BaseQmlDebuggerClient(QmlDebug::QmlDebugConnection* client, QLatin1String clientName)
- : QmlDebugClient(clientName, client),
- d(new BaseQmlDebuggerClientPrivate())
-{
-}
-
-BaseQmlDebuggerClient::~BaseQmlDebuggerClient()
-{
- delete d;
-}
-
-bool BaseQmlDebuggerClient::acceptsBreakpoint(Breakpoint /*bp*/)
-{
- return false;
-}
-
-void BaseQmlDebuggerClient::stateChanged(State state)
-{
- emit newState(state);
-}
-
-void BaseQmlDebuggerClient::sendMessage(const QByteArray &msg)
-{
- if (state() == Enabled)
- QmlDebugClient::sendMessage(msg);
- else
- d->sendBuffer.append(msg);
-}
-
-void BaseQmlDebuggerClient::flushSendBuffer()
-{
- QTC_ASSERT(state() == Enabled, return);
- foreach (const QByteArray &msg, d->sendBuffer)
- QmlDebugClient::sendMessage(msg);
- d->sendBuffer.clear();
-}
-
-} // Internal
-} // Debugger
diff --git a/src/plugins/debugger/qml/baseqmldebuggerclient.h b/src/plugins/debugger/qml/baseqmldebuggerclient.h
deleted file mode 100644
index 47435fbf99..0000000000
--- a/src/plugins/debugger/qml/baseqmldebuggerclient.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef BASEQMLDEBUGGERCLIENT_H
-#define BASEQMLDEBUGGERCLIENT_H
-
-#include <debugger/debuggerengine.h>
-#include <qmldebug/qmldebugclient.h>
-
-namespace Debugger {
-namespace Internal {
-
-class WatchData;
-class WatchItem;
-class BreakHandler;
-class BreakpointModelId;
-class QmlEngine;
-class BaseQmlDebuggerClientPrivate;
-
-class BaseQmlDebuggerClient : public QmlDebug::QmlDebugClient
-{
- Q_OBJECT
-
-public:
- BaseQmlDebuggerClient(QmlDebug::QmlDebugConnection* client, QLatin1String clientName);
- virtual ~BaseQmlDebuggerClient();
-
- virtual void startSession() = 0;
- virtual void endSession() = 0;
- virtual void resetSession() = 0;
-
- virtual void executeStep() = 0;
- virtual void executeStepOut() = 0;
- virtual void executeNext() = 0;
- virtual void executeStepI() = 0;
-
- virtual void executeRunToLine(const ContextData &data) = 0;
-
- virtual void continueInferior() = 0;
- virtual void interruptInferior() = 0;
-
- virtual void activateFrame(int index) = 0;
-
- virtual bool acceptsBreakpoint(Breakpoint bp);
- virtual void insertBreakpoint(Breakpoint bp, int adjustedLine,
- int adjustedColumn = -1) = 0;
- virtual void removeBreakpoint(Breakpoint bp) = 0;
- virtual void changeBreakpoint(Breakpoint bp) = 0;
- virtual void synchronizeBreakpoints() = 0;
-
- virtual void assignValueInDebugger(const WatchData *data,
- const QString &expression,
- const QVariant &valueV) = 0;
-
- virtual void updateWatchData(const WatchData &data) = 0;
- virtual void executeDebuggerCommand(const QString &command) = 0;
-
- virtual void synchronizeWatchers(const QStringList &watchers) = 0;
-
- virtual void expandObject(const QByteArray &iname, quint64 objectId) = 0;
-
- virtual void setEngine(QmlEngine *engine) = 0;
-
- virtual void getSourceFiles() {}
-
- void flushSendBuffer();
-
-signals:
- void newState(QmlDebug::QmlDebugClient::State state);
- void stackFrameCompleted();
-
-protected:
- virtual void stateChanged(State state);
- void sendMessage(const QByteArray &msg);
-
-private:
- BaseQmlDebuggerClientPrivate *d;
- friend class BaseQmlDebuggerClientPrivate;
-};
-
-} // Internal
-} // Debugger
-
-#endif // BASEQMLDEBUGGERCLIENT_H
diff --git a/src/plugins/debugger/qml/qml.pri b/src/plugins/debugger/qml/qml.pri
index 3dd714070d..18ed7fe1f5 100644
--- a/src/plugins/debugger/qml/qml.pri
+++ b/src/plugins/debugger/qml/qml.pri
@@ -1,10 +1,7 @@
HEADERS += \
$$PWD/qmlengine.h \
- $$PWD/qmladapter.h \
- $$PWD/baseqmldebuggerclient.h \
+ $$PWD/qmlengineutils.h \
$$PWD/qmlcppengine.h \
- $$PWD/qscriptdebuggerclient.h \
- $$PWD/qmlv8debuggerclient.h \
$$PWD/interactiveinterpreter.h \
$$PWD/qmlv8debuggerclientconstants.h \
$$PWD/qmlinspectoragent.h \
@@ -12,11 +9,8 @@ HEADERS += \
SOURCES += \
$$PWD/qmlengine.cpp \
- $$PWD/qmladapter.cpp \
- $$PWD/baseqmldebuggerclient.cpp \
+ $$PWD/qmlengineutils.cpp \
$$PWD/qmlcppengine.cpp \
- $$PWD/qscriptdebuggerclient.cpp \
- $$PWD/qmlv8debuggerclient.cpp \
$$PWD/interactiveinterpreter.cpp \
$$PWD/qmlinspectoragent.cpp \
$$PWD/qmlinspectoradapter.cpp
diff --git a/src/plugins/debugger/qml/qmladapter.cpp b/src/plugins/debugger/qml/qmladapter.cpp
deleted file mode 100644
index 73f29d0400..0000000000
--- a/src/plugins/debugger/qml/qmladapter.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#include "qmladapter.h"
-
-#include <debugger/debuggerstringutils.h>
-#include "qmlengine.h"
-#include "qmlv8debuggerclient.h"
-#include "qscriptdebuggerclient.h"
-
-#include <utils/qtcassert.h>
-
-#include <QDebug>
-
-using namespace QmlDebug;
-
-namespace Debugger {
-namespace Internal {
-
-/*!
- QmlAdapter manages the connection & clients for QML/JS debugging.
- */
-
-QmlAdapter::QmlAdapter(DebuggerEngine *engine, QObject *parent)
- : QObject(parent)
- , m_engine(engine)
- , m_qmlClient(0)
- , m_conn(0)
- , m_msgClient(0)
-{
- m_connectionTimer.setInterval(4000);
- m_connectionTimer.setSingleShot(true);
- connect(&m_connectionTimer, &QTimer::timeout, this, &QmlAdapter::checkConnectionState);
-
- m_conn = new QmlDebugConnection(this);
- connect(m_conn, &QmlDebugConnection::stateMessage,
- this, &QmlAdapter::showConnectionStateMessage);
- connect(m_conn, &QmlDebugConnection::errorMessage,
- this, &QmlAdapter::showConnectionErrorMessage);
- connect(m_conn, &QmlDebugConnection::error,
- this, &QmlAdapter::connectionErrorOccurred);
- connect(m_conn, &QmlDebugConnection::opened,
- &m_connectionTimer, &QTimer::stop);
- connect(m_conn, &QmlDebugConnection::opened,
- this, &QmlAdapter::connected);
- connect(m_conn, &QmlDebugConnection::closed,
- this, &QmlAdapter::disconnected);
-
- createDebuggerClients();
- m_msgClient = new QDebugMessageClient(m_conn);
- connect(m_msgClient, &QDebugMessageClient::newState, this, &QmlAdapter::clientStateChanged);
-
-}
-
-QmlAdapter::~QmlAdapter()
-{
-}
-
-void QmlAdapter::beginConnectionTcp(const QString &address, quint16 port)
-{
- if (m_engine.isNull() || !m_conn || m_conn->isOpen())
- return;
-
- m_conn->connectToHost(address, port);
-
- //A timeout to check the connection state
- m_connectionTimer.start();
-}
-
-void QmlAdapter::closeConnection()
-{
- if (m_connectionTimer.isActive()) {
- m_connectionTimer.stop();
- } else {
- if (m_conn)
- m_conn->close();
- }
-}
-
-void QmlAdapter::connectionErrorOccurred(QDebugSupport::Error error)
-{
- // this is only an error if we are already connected and something goes wrong.
- if (isConnected()) {
- emit connectionError(error);
- } else {
- m_connectionTimer.stop();
- emit connectionStartupFailed();
- }
-}
-
-void QmlAdapter::clientStateChanged(QmlDebugClient::State state)
-{
- QString serviceName;
- float version = 0;
- if (QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender())) {
- serviceName = client->name();
- version = client->remoteVersion();
- }
-
- logServiceStateChange(serviceName, version, state);
-}
-
-void QmlAdapter::debugClientStateChanged(QmlDebugClient::State state)
-{
- if (state != QmlDebugClient::Enabled)
- return;
- QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender());
- QTC_ASSERT(client, return);
-
- m_qmlClient = qobject_cast<BaseQmlDebuggerClient *>(client);
- m_qmlClient->startSession();
-}
-
-void QmlAdapter::checkConnectionState()
-{
- if (!isConnected()) {
- closeConnection();
- emit connectionStartupFailed();
- }
-}
-
-bool QmlAdapter::isConnected() const
-{
- return m_conn && m_qmlClient && m_conn->isOpen();
-}
-
-void QmlAdapter::createDebuggerClients()
-{
- QScriptDebuggerClient *debugClient1 = new QScriptDebuggerClient(m_conn);
- connect(debugClient1, &QScriptDebuggerClient::newState,
- this, &QmlAdapter::clientStateChanged);
- connect(debugClient1, &QScriptDebuggerClient::newState,
- this, &QmlAdapter::debugClientStateChanged);
-
- QmlV8DebuggerClient *debugClient2 = new QmlV8DebuggerClient(m_conn);
- connect(debugClient2, &QmlV8DebuggerClient::newState,
- this, &QmlAdapter::clientStateChanged);
- connect(debugClient2, &QmlV8DebuggerClient::newState,
- this, &QmlAdapter::debugClientStateChanged);
-
- m_debugClients.insert(debugClient1->name(),debugClient1);
- m_debugClients.insert(debugClient2->name(),debugClient2);
-
- debugClient1->setEngine((QmlEngine*)(m_engine.data()));
- debugClient2->setEngine((QmlEngine*)(m_engine.data()));
-}
-
-QmlDebugConnection *QmlAdapter::connection() const
-{
- return m_conn;
-}
-
-DebuggerEngine *QmlAdapter::debuggerEngine() const
-{
- return m_engine.data();
-}
-
-void QmlAdapter::showConnectionStateMessage(const QString &message)
-{
- if (!m_engine.isNull())
- m_engine.data()->showMessage(_("QML Debugger: ") + message, LogStatus);
-}
-
-void QmlAdapter::showConnectionErrorMessage(const QString &message)
-{
- if (!m_engine.isNull())
- m_engine.data()->showMessage(_("QML Debugger: ") + message, LogError);
-}
-
-BaseQmlDebuggerClient *QmlAdapter::activeDebuggerClient() const
-{
- return m_qmlClient;
-}
-
-QHash<QString, BaseQmlDebuggerClient*> QmlAdapter::debuggerClients() const
-{
- return m_debugClients;
-}
-
-QDebugMessageClient *QmlAdapter::messageClient() const
-{
- return m_msgClient;
-}
-
-void QmlAdapter::logServiceStateChange(const QString &service, float version,
- QmlDebugClient::State newState)
-{
- switch (newState) {
- case QmlDebugClient::Unavailable: {
- showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'unavailable'.").
- arg(service).arg(QString::number(version)));
- break;
- }
- case QmlDebugClient::Enabled: {
- showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'enabled'.").
- arg(service).arg(QString::number(version)));
- break;
- }
-
- case QmlDebugClient::NotConnected: {
- showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'not connected'.").
- arg(service).arg(QString::number(version)));
- break;
- }
- }
-}
-
-void QmlAdapter::logServiceActivity(const QString &service, const QString &logMessage)
-{
- if (!m_engine.isNull())
- m_engine.data()->showMessage(service + QLatin1Char(' ') + logMessage, LogDebug);
-}
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/qml/qmladapter.h b/src/plugins/debugger/qml/qmladapter.h
deleted file mode 100644
index e9f3936878..0000000000
--- a/src/plugins/debugger/qml/qmladapter.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef QMLADAPTER_H
-#define QMLADAPTER_H
-
-#include <qmldebug/qmldebugclient.h>
-
-#include <QPointer>
-#include <QTimer>
-
-namespace QmlDebug {
-class BaseEngineDebugClient;
-class QmlDebugConnection;
-class QDebugMessageClient;
-}
-
-namespace Debugger {
-namespace Internal {
-
-class BaseQmlDebuggerClient;
-class DebuggerEngine;
-class QmlAdapterPrivate;
-
-class QmlAdapter : public QObject
-{
- Q_OBJECT
-
-public:
- explicit QmlAdapter(DebuggerEngine *engine, QObject *parent = 0);
- virtual ~QmlAdapter();
-
- void beginConnectionTcp(const QString &address, quint16 port);
- void closeConnection();
-
- QmlDebug::QmlDebugConnection *connection() const;
- DebuggerEngine *debuggerEngine() const;
-
- BaseQmlDebuggerClient *activeDebuggerClient() const;
- QHash<QString, BaseQmlDebuggerClient*> debuggerClients() const;
-
- QmlDebug::QDebugMessageClient *messageClient() const;
-
-public slots:
- void logServiceStateChange(const QString &service, float version,
- QmlDebug::QmlDebugClient::State newState);
- void logServiceActivity(const QString &service, const QString &logMessage);
-
-signals:
- void connected();
- void disconnected();
- void connectionStartupFailed();
- void connectionError(QDebugSupport::Error error);
- void serviceConnectionError(const QString serviceName);
-
-private slots:
- void connectionErrorOccurred(QDebugSupport::Error socketError);
- void clientStateChanged(QmlDebug::QmlDebugClient::State state);
- void debugClientStateChanged(QmlDebug::QmlDebugClient::State state);
- void checkConnectionState();
- void showConnectionStateMessage(const QString &message);
- void showConnectionErrorMessage(const QString &message);
-
-private:
- bool isConnected() const;
- void createDebuggerClients();
-
-private:
- QPointer<DebuggerEngine> m_engine;
- BaseQmlDebuggerClient *m_qmlClient;
- QTimer m_connectionTimer;
- QmlDebug::QmlDebugConnection *m_conn;
- QHash<QString, BaseQmlDebuggerClient*> m_debugClients;
- QmlDebug::QDebugMessageClient *m_msgClient;
-};
-
-} // namespace Internal
-} // namespace Debugger
-
-#endif // QMLADAPTER_H
diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp
index c2b2ca3246..46e2796446 100644
--- a/src/plugins/debugger/qml/qmlengine.cpp
+++ b/src/plugins/debugger/qml/qmlengine.cpp
@@ -29,46 +29,53 @@
****************************************************************************/
#include "qmlengine.h"
-#include "baseqmldebuggerclient.h"
+
+#include "interactiveinterpreter.h"
+#include "qmlinspectoradapter.h"
#include "qmlinspectoragent.h"
+#include "qmlv8debuggerclientconstants.h"
+#include "qmlengineutils.h"
+#include <debugger/breakhandler.h>
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerinternalconstants.h>
-#include <debugger/debuggermainwindow.h>
#include <debugger/debuggerruncontrol.h>
-#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggerstringutils.h>
#include <debugger/debuggertooltipmanager.h>
-#include <debugger/localsandexpressionswindow.h>
+#include <debugger/sourcefileshandler.h>
+#include <debugger/stackhandler.h>
#include <debugger/threaddata.h>
+#include <debugger/watchhandler.h>
#include <debugger/watchwindow.h>
-#include <debugger/breakhandler.h>
-#include <debugger/stackhandler.h>
-#include <debugger/watchhandler.h>
-#include <debugger/sourcefileshandler.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/helpmanager.h>
+#include <coreplugin/icore.h>
+
+#include <projectexplorer/applicationlauncher.h>
#include <qmljseditor/qmljseditorconstants.h>
-#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/consolemanagerinterface.h>
-#include <utils/qtcassert.h>
-
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
-#include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/helpmanager.h>
-#include <coreplugin/icore.h>
+
+#include <utils/qtcassert.h>
#include <QDebug>
#include <QDir>
#include <QDockWidget>
+#include <QFileInfo>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
#include <QMessageBox>
#include <QPlainTextEdit>
+#include <QTimer>
-#define DEBUG_QML 1
+#define DEBUG_QML 0
#if DEBUG_QML
# define SDEBUG(s) qDebug() << s
#else
@@ -76,185 +83,139 @@
#endif
# define XSDEBUG(s) qDebug() << s
+using namespace Core;
+using namespace ProjectExplorer;
+using namespace QmlDebug;
using namespace QmlJS;
-using namespace AST;
+using namespace TextEditor;
namespace Debugger {
namespace Internal {
-static QTreeView *inspectorTreeView()
+enum Exceptions
{
- return Internal::inspectorView();
-}
+ NoExceptions,
+ UncaughtExceptions,
+ AllExceptions
+};
-class ASTWalker : public Visitor
+enum StepAction
{
-public:
- void operator()(Node *ast, quint32 *l, quint32 *c)
- {
- done = false;
- line = l;
- column = c;
- Node::accept(ast, this);
- }
-
- bool preVisit(Node *ast)
- {
- return ast->lastSourceLocation().startLine >= *line && !done;
- }
-
- //Case 1: Breakpoint is between sourceStart(exclusive) and
- // sourceEnd(inclusive) --> End tree walk.
- //Case 2: Breakpoint is on sourceStart --> Check for the start
- // of the first executable code. Set the line number and
- // column number. End tree walk.
- //Case 3: Breakpoint is on "unbreakable" code --> Find the next "breakable"
- // code and check for Case 2. End tree walk.
-
- //Add more types when suitable.
-
- bool visit(UiScriptBinding *ast)
- {
- if (!ast->statement)
- return true;
-
- quint32 sourceStartLine = ast->firstSourceLocation().startLine;
- quint32 statementStartLine;
- quint32 statementColumn;
-
- if (ast->statement->kind == Node::Kind_ExpressionStatement) {
- statementStartLine = ast->statement->firstSourceLocation().
- startLine;
- statementColumn = ast->statement->firstSourceLocation().startColumn;
-
- } else if (ast->statement->kind == Node::Kind_Block) {
- Block *block = static_cast<Block *>(ast->statement);
- if (!block || !block->statements)
- return true;
- statementStartLine = block->statements->firstSourceLocation().
- startLine;
- statementColumn = block->statements->firstSourceLocation().
- startColumn;
-
- } else {
- return true;
- }
-
-
- //Case 1
- //Check for possible relocation within the binding statement
-
- //Rewritten to (function <token>() { { }})
- //The offset 16 is position of inner lbrace without token length.
- const int offset = 16;
-
- //Case 2
- if (statementStartLine == *line) {
- if (sourceStartLine == *line)
- *column = offset + ast->qualifiedId->identifierToken.length;
- done = true;
- }
-
- //Case 3
- if (statementStartLine > *line) {
- *line = statementStartLine;
- if (sourceStartLine == *line)
- *column = offset + ast->qualifiedId->identifierToken.length;
- else
- *column = statementColumn;
- done = true;
- }
- return true;
- }
-
- bool visit(FunctionDeclaration *ast) {
- quint32 sourceStartLine = ast->firstSourceLocation().startLine;
- quint32 sourceStartColumn = ast->firstSourceLocation().startColumn;
- quint32 statementStartLine = ast->body->firstSourceLocation().startLine;
- quint32 statementColumn = ast->body->firstSourceLocation().startColumn;
-
- //Case 1
- //Check for possible relocation within the function declaration
-
- //Case 2
- if (statementStartLine == *line) {
- if (sourceStartLine == *line)
- *column = statementColumn - sourceStartColumn + 1;
- done = true;
- }
+ Continue,
+ StepIn,
+ StepOut,
+ Next
+};
- //Case 3
- if (statementStartLine > *line) {
- *line = statementStartLine;
- if (sourceStartLine == *line)
- *column = statementColumn - sourceStartColumn + 1;
- else
- *column = statementColumn;
- done = true;
- }
- return true;
- }
+struct QmlV8ObjectData
+{
+ int handle;
+ QByteArray name;
+ QByteArray type;
+ QVariant value;
+ QVariantList properties;
+};
- bool visit(EmptyStatement *ast)
- {
- *line = ast->lastSourceLocation().startLine + 1;
- return true;
- }
-
- bool visit(VariableStatement *ast) { test(ast); return true; }
- bool visit(VariableDeclarationList *ast) { test(ast); return true; }
- bool visit(VariableDeclaration *ast) { test(ast); return true; }
- bool visit(ExpressionStatement *ast) { test(ast); return true; }
- bool visit(IfStatement *ast) { test(ast); return true; }
- bool visit(DoWhileStatement *ast) { test(ast); return true; }
- bool visit(WhileStatement *ast) { test(ast); return true; }
- bool visit(ForStatement *ast) { test(ast); return true; }
- bool visit(LocalForStatement *ast) { test(ast); return true; }
- bool visit(ForEachStatement *ast) { test(ast); return true; }
- bool visit(LocalForEachStatement *ast) { test(ast); return true; }
- bool visit(ContinueStatement *ast) { test(ast); return true; }
- bool visit(BreakStatement *ast) { test(ast); return true; }
- bool visit(ReturnStatement *ast) { test(ast); return true; }
- bool visit(WithStatement *ast) { test(ast); return true; }
- bool visit(SwitchStatement *ast) { test(ast); return true; }
- bool visit(CaseBlock *ast) { test(ast); return true; }
- bool visit(CaseClauses *ast) { test(ast); return true; }
- bool visit(CaseClause *ast) { test(ast); return true; }
- bool visit(DefaultClause *ast) { test(ast); return true; }
- bool visit(LabelledStatement *ast) { test(ast); return true; }
- bool visit(ThrowStatement *ast) { test(ast); return true; }
- bool visit(TryStatement *ast) { test(ast); return true; }
- bool visit(Catch *ast) { test(ast); return true; }
- bool visit(Finally *ast) { test(ast); return true; }
- bool visit(FunctionExpression *ast) { test(ast); return true; }
- bool visit(DebuggerStatement *ast) { test(ast); return true; }
-
- void test(Node *ast)
- {
- quint32 statementStartLine = ast->firstSourceLocation().startLine;
- //Case 1/2
- if (statementStartLine <= *line &&
- *line <= ast->lastSourceLocation().startLine)
- done = true;
-
- //Case 3
- if (statementStartLine > *line) {
- *line = statementStartLine;
- *column = ast->firstSourceLocation().startColumn;
- done = true;
- }
- }
+class QmlEnginePrivate : QmlDebugClient
+{
+public:
+ QmlEnginePrivate(QmlEngine *engine_, QmlDebugConnection *connection_)
+ : QmlDebugClient(QLatin1String("V8Debugger"), connection_),
+ engine(engine_),
+ inspectorAdapter(engine, connection_),
+ connection(connection_)
+ {}
+
+ void sendMessage(const QByteArray &msg);
+ void messageReceived(const QByteArray &data);
+ void stateChanged(State state);
+
+ void connect();
+ void disconnect();
+
+ void continueDebugging(StepAction stepAction);
+
+ void evaluate(const QString expr, bool global = false, bool disableBreak = false,
+ int frame = -1, bool addContext = false);
+ void lookup(const QList<int> handles, bool includeSource = false);
+ void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
+ void frame(int number = -1);
+ void scope(int number = -1, int frameNumber = -1);
+ void scripts(int types = 4, const QList<int> ids = QList<int>(),
+ bool includeSource = false, const QVariant filter = QVariant());
+
+ void setBreakpoint(const QString type, const QString target,
+ bool enabled = true,int line = 0, int column = 0,
+ const QString condition = QString(), int ignoreCount = -1);
+ void clearBreakpoint(int breakpoint);
+ void setExceptionBreak(Exceptions type, bool enabled = false);
+
+ void version();
+ void clearCache();
+
+ void sendAndLogV8Request(const QJsonObject &request);
+
+ QByteArray packMessage(const QByteArray &type, const QByteArray &message = QByteArray());
+ QJsonObject initObject();
+
+ void expandObject(const QByteArray &iname, quint64 objectId);
+ void flushSendBuffer();
+
+ void handleBacktrace(const QVariant &bodyVal, const QVariant &refsVal);
+ void handleLookup(const QVariant &bodyVal, const QVariant &refsVal);
+ void handleEvaluate(int sequence, bool success, const QVariant &bodyVal, const QVariant &refsVal);
+ void handleFrame(const QVariant &bodyVal, const QVariant &refsVal);
+ void handleScope(const QVariant &bodyVal, const QVariant &refsVal);
+ StackFrame extractStackFrame(const QVariant &bodyVal, const QVariant &refsVal);
+
+ bool canEvaluateScript(const QString &script);
+ void updateScriptSource(const QString &fileName, int lineOffset, int columnOffset, const QString &source);
- bool done;
- quint32 *line;
- quint32 *column;
+public:
+ int sequence = -1;
+ QmlEngine *engine;
+ QHash<BreakpointModelId, int> breakpoints;
+ QHash<int, BreakpointModelId> breakpointsSync;
+ QList<int> breakpointsTemp;
+
+ QHash<int, QString> evaluatingExpression;
+ QHash<int, QByteArray> localsAndWatchers;
+ QList<int> updateLocalsAndWatchers;
+ QList<int> debuggerCommands;
+
+ //Cache
+ QList<int> currentFrameScopes;
+ QHash<int, int> stackIndexLookup;
+
+ StepAction previousStepAction = Continue;
+
+ QList<QByteArray> sendBuffer;
+
+ QHash<QString, QTextDocument*> sourceDocuments;
+ QHash<QString, QWeakPointer<BaseTextEditor> > sourceEditors;
+ InteractiveInterpreter interpreter;
+ ApplicationLauncher applicationLauncher;
+ QmlInspectorAdapter inspectorAdapter;
+ QmlOutputParser outputParser;
+
+ QTimer noDebugOutputTimer;
+ QHash<QString,Breakpoint> pendingBreakpoints;
+ QList<quint32> queryIds;
+ bool retryOnConnectFail = false;
+ bool automaticConnect = false;
+
+ QTimer connectionTimer;
+ QmlDebug::QmlDebugConnection *connection;
+ QmlDebug::QDebugMessageClient *msgClient = 0;
};
-ConsoleManagerInterface *qmlConsoleManager()
+static void updateDocument(IDocument *document, const QTextDocument *textDocument)
{
- return ConsoleManagerInterface::instance();
+ if (auto baseTextDocument = qobject_cast<TextDocument *>(document))
+ baseTextDocument->document()->setPlainText(textDocument->toPlainText());
}
+
///////////////////////////////////////////////////////////////////////
//
// QmlEngine
@@ -262,94 +223,97 @@ ConsoleManagerInterface *qmlConsoleManager()
///////////////////////////////////////////////////////////////////////
QmlEngine::QmlEngine(const DebuggerRunParameters &startParameters, DebuggerEngine *masterEngine)
- : DebuggerEngine(startParameters)
- , m_adapter(this)
- , m_inspectorAdapter(&m_adapter, this)
- , m_retryOnConnectFail(false)
- , m_automaticConnect(false)
+ : DebuggerEngine(startParameters),
+ d(new QmlEnginePrivate(this, new QmlDebugConnection(this)))
{
setObjectName(QLatin1String("QmlEngine"));
if (masterEngine)
setMasterEngine(masterEngine);
- connect(&m_adapter, SIGNAL(connectionError(QDebugSupport::Error)),
- SLOT(connectionError(QDebugSupport::Error)));
- connect(&m_adapter, SIGNAL(serviceConnectionError(QString)),
- SLOT(serviceConnectionError(QString)));
- connect(&m_adapter, SIGNAL(connected()),
- SLOT(connectionEstablished()));
- connect(&m_adapter, SIGNAL(connectionStartupFailed()),
- SLOT(connectionStartupFailed()));
-
- connect(stackHandler(), SIGNAL(stackChanged()),
- SLOT(updateCurrentContext()));
- connect(stackHandler(), SIGNAL(currentIndexChanged()),
+ connect(stackHandler(), &StackHandler::stackChanged,
+ this, &QmlEngine::updateCurrentContext);
+ connect(stackHandler(), &StackHandler::currentIndexChanged,
+ this, &QmlEngine::updateCurrentContext);
+ connect(inspectorView(), SIGNAL(currentIndexChanged(QModelIndex)),
SLOT(updateCurrentContext()));
- connect(inspectorTreeView(), SIGNAL(currentIndexChanged(QModelIndex)),
- SLOT(updateCurrentContext()));
- connect(m_inspectorAdapter.agent(), SIGNAL(
- expressionResult(quint32,QVariant)),
- SLOT(expressionEvaluated(quint32,QVariant)));
- connect(m_adapter.messageClient(),
- SIGNAL(message(QtMsgType,QString,
- QmlDebug::QDebugContextInfo)),
- SLOT(appendDebugOutput(QtMsgType,QString,
- QmlDebug::QDebugContextInfo)));
-
-
- connect(&m_applicationLauncher,
- SIGNAL(processExited(int,QProcess::ExitStatus)),
- SLOT(disconnected()));
- connect(&m_applicationLauncher,
- SIGNAL(appendMessage(QString,Utils::OutputFormat)),
- SLOT(appendMessage(QString,Utils::OutputFormat)));
- connect(&m_applicationLauncher,
- SIGNAL(processStarted()),
- &m_noDebugOutputTimer,
- SLOT(start()));
-
- m_outputParser.setNoOutputText(ProjectExplorer::ApplicationLauncher
- ::msgWinCannotRetrieveDebuggingOutput());
- connect(&m_outputParser, SIGNAL(waitingForConnectionOnPort(quint16)),
- this, SLOT(beginConnection(quint16)));
- connect(&m_outputParser, SIGNAL(noOutputMessage()),
- this, SLOT(tryToConnect()));
- connect(&m_outputParser, SIGNAL(errorMessage(QString)),
- this, SLOT(appStartupFailed(QString)));
+ connect(d->inspectorAdapter.agent(), &QmlInspectorAgent::expressionResult,
+ this, &QmlEngine::expressionEvaluated);
+
+ connect(&d->applicationLauncher, &ApplicationLauncher::processExited,
+ this, &QmlEngine::disconnected);
+ connect(&d->applicationLauncher, &ApplicationLauncher::appendMessage,
+ this, &QmlEngine::appendMessage);
+ connect(&d->applicationLauncher, &ApplicationLauncher::processStarted,
+ &d->noDebugOutputTimer, static_cast<void(QTimer::*)()>(&QTimer::start));
+
+ d->outputParser.setNoOutputText(ApplicationLauncher::msgWinCannotRetrieveDebuggingOutput());
+ connect(&d->outputParser, &QmlOutputParser::waitingForConnectionOnPort,
+ this, &QmlEngine::beginConnection);
+ connect(&d->outputParser, &QmlOutputParser::noOutputMessage,
+ this, [this] { tryToConnect(); });
+ connect(&d->outputParser, &QmlOutputParser::errorMessage,
+ this, &QmlEngine::appStartupFailed);
// Only wait 8 seconds for the 'Waiting for connection' on application output,
// then just try to connect (application output might be redirected / blocked)
- m_noDebugOutputTimer.setSingleShot(true);
- m_noDebugOutputTimer.setInterval(8000);
- connect(&m_noDebugOutputTimer, SIGNAL(timeout()), this, SLOT(tryToConnect()));
+ d->noDebugOutputTimer.setSingleShot(true);
+ d->noDebugOutputTimer.setInterval(8000);
+ connect(&d->noDebugOutputTimer, SIGNAL(timeout()), this, SLOT(tryToConnect()));
- ModelManagerInterface *mmIface = ModelManagerInterface::instance();
- if (mmIface) {
- connect(ModelManagerInterface::instance(), SIGNAL(documentUpdated(QmlJS::Document::Ptr)),
- this, SLOT(documentUpdated(QmlJS::Document::Ptr)));
+ if (auto mmIface = ModelManagerInterface::instance()) {
+ connect(mmIface, &ModelManagerInterface::documentUpdated,
+ this, &QmlEngine::documentUpdated);
}
// we won't get any debug output
if (startParameters.useTerminal) {
- m_noDebugOutputTimer.setInterval(0);
- m_retryOnConnectFail = true;
- m_automaticConnect = true;
+ d->noDebugOutputTimer.setInterval(0);
+ d->retryOnConnectFail = true;
+ d->automaticConnect = true;
}
- if (qmlConsoleManager())
- qmlConsoleManager()->setScriptEvaluator(this);
+
+ if (auto consoleManager = ConsoleManagerInterface::instance())
+ consoleManager->setScriptEvaluator(this);
+
+
+ d->connectionTimer.setInterval(4000);
+ d->connectionTimer.setSingleShot(true);
+ connect(&d->connectionTimer, &QTimer::timeout,
+ this, &QmlEngine::checkConnectionState);
+
+ connect(d->connection, &QmlDebugConnection::stateMessage,
+ this, &QmlEngine::showConnectionStateMessage);
+ connect(d->connection, &QmlDebugConnection::errorMessage,
+ this, &QmlEngine::showConnectionErrorMessage);
+ connect(d->connection, &QmlDebugConnection::error,
+ this, &QmlEngine::connectionErrorOccurred);
+ connect(d->connection, &QmlDebugConnection::opened,
+ &d->connectionTimer, &QTimer::stop);
+ connect(d->connection, &QmlDebugConnection::opened,
+ this, &QmlEngine::connectionEstablished);
+ connect(d->connection, &QmlDebugConnection::closed,
+ this, &QmlEngine::disconnected);
+
+ d->msgClient = new QDebugMessageClient(d->connection);
+ connect(d->msgClient, &QDebugMessageClient::newState,
+ this, &QmlEngine::clientStateChanged);
+ connect(d->msgClient, &QDebugMessageClient::message,
+ this, &appendDebugOutput);
}
QmlEngine::~QmlEngine()
{
- QSet<Core::IDocument *> documentsToClose;
+ QSet<IDocument *> documentsToClose;
- QHash<QString, QWeakPointer<TextEditor::BaseTextEditor> >::iterator iter;
- for (iter = m_sourceEditors.begin(); iter != m_sourceEditors.end(); ++iter) {
- QWeakPointer<TextEditor::BaseTextEditor> textEditPtr = iter.value();
+ QHash<QString, QWeakPointer<BaseTextEditor> >::iterator iter;
+ for (iter = d->sourceEditors.begin(); iter != d->sourceEditors.end(); ++iter) {
+ QWeakPointer<BaseTextEditor> textEditPtr = iter.value();
if (textEditPtr)
documentsToClose << textEditPtr.data()->document();
}
- Core::EditorManager::closeDocuments(documentsToClose.toList());
+ EditorManager::closeDocuments(documentsToClose.toList());
+
+ delete d;
}
void QmlEngine::setupInferior()
@@ -358,7 +322,7 @@ void QmlEngine::setupInferior()
notifyInferiorSetupOk();
- if (m_automaticConnect)
+ if (d->automaticConnect)
beginConnection();
}
@@ -373,7 +337,8 @@ void QmlEngine::connectionEstablished()
if (!watchHandler()->watcherNames().isEmpty())
synchronizeWatchers();
- connect(watchModel(),SIGNAL(layoutChanged()),this,SLOT(synchronizeWatchers()));
+ connect(watchModel(), &QAbstractItemModel::layoutChanged,
+ this, &QmlEngine::synchronizeWatchers);
if (state() == EngineRunRequested)
notifyEngineRunAndInferiorRunOk();
@@ -382,13 +347,13 @@ void QmlEngine::connectionEstablished()
void QmlEngine::tryToConnect(quint16 port)
{
showMessage(QLatin1String("QML Debugger: No application output received in time, trying to connect ..."), LogStatus);
- m_retryOnConnectFail = true;
+ d->retryOnConnectFail = true;
if (state() == EngineRunRequested) {
if (isSlaveEngine()) {
// Probably cpp is being debugged and hence we did not get the output yet.
if (!masterEngine()->isDying()) {
- m_noDebugOutputTimer.setInterval(4000);
- m_noDebugOutputTimer.start();
+ d->noDebugOutputTimer.setInterval(4000);
+ d->noDebugOutputTimer.start();
}
else
appStartupFailed(tr("No application output received in time"));
@@ -396,15 +361,15 @@ void QmlEngine::tryToConnect(quint16 port)
beginConnection(port);
}
} else {
- m_automaticConnect = true;
+ d->automaticConnect = true;
}
}
void QmlEngine::beginConnection(quint16 port)
{
- m_noDebugOutputTimer.stop();
+ d->noDebugOutputTimer.stop();
- if (state() != EngineRunRequested && m_retryOnConnectFail)
+ if (state() != EngineRunRequested && d->retryOnConnectFail)
return;
QTC_ASSERT(state() == EngineRunRequested, return);
@@ -428,19 +393,24 @@ void QmlEngine::beginConnection(quint16 port)
if (runParameters().qmlServerPort > 0)
port = runParameters().qmlServerPort;
- m_adapter.beginConnectionTcp(host, port);
-}
+ if (!d->connection || d->connection->isOpen())
+ return;
+ d->connection->connectToHost(host, port);
+
+ //A timeout to check the connection state
+ d->connectionTimer.start();
+}
void QmlEngine::connectionStartupFailed()
{
- if (m_retryOnConnectFail) {
+ if (d->retryOnConnectFail) {
// retry after 3 seconds ...
QTimer::singleShot(3000, this, SLOT(beginConnection()));
return;
}
- QMessageBox *infoBox = new QMessageBox(Core::ICore::mainWindow());
+ QMessageBox *infoBox = new QMessageBox(ICore::mainWindow());
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(tr("Qt Creator"));
infoBox->setText(tr("Could not connect to the in-process QML debugger."
@@ -450,8 +420,8 @@ void QmlEngine::connectionStartupFailed()
infoBox->setDefaultButton(QMessageBox::Retry);
infoBox->setModal(true);
- connect(infoBox, SIGNAL(finished(int)),
- this, SLOT(errorMessageBoxFinished(int)));
+ connect(infoBox, &QDialog::finished,
+ this, &QmlEngine::errorMessageBoxFinished);
infoBox->show();
}
@@ -462,14 +432,14 @@ void QmlEngine::appStartupFailed(const QString &errorMessage)
"\n%1").arg(errorMessage);
if (isMasterEngine()) {
- QMessageBox *infoBox = new QMessageBox(Core::ICore::mainWindow());
+ QMessageBox *infoBox = new QMessageBox(ICore::mainWindow());
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(tr("Qt Creator"));
infoBox->setText(error);
infoBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Help);
infoBox->setDefaultButton(QMessageBox::Ok);
- connect(infoBox, SIGNAL(finished(int)),
- this, SLOT(errorMessageBoxFinished(int)));
+ connect(infoBox, &QDialog::finished,
+ this, &QmlEngine::errorMessageBoxFinished);
infoBox->show();
} else {
showMessage(error, StatusBar);
@@ -486,7 +456,7 @@ void QmlEngine::errorMessageBoxFinished(int result)
break;
}
case QMessageBox::Help: {
- Core::HelpManager::handleHelpRequest(QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"));
+ HelpManager::handleHelpRequest(QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"));
// fall through
}
default:
@@ -500,37 +470,15 @@ void QmlEngine::errorMessageBoxFinished(int result)
}
}
-void QmlEngine::connectionError(QDebugSupport::Error error)
-{
- if (error == QDebugSupport::RemoteClosedConnectionError)
- showMessage(tr("QML Debugger: Remote host closed connection."), StatusBar);
-
- if (!isSlaveEngine()) { // normal flow for slave engine when gdb exits
- notifyInferiorSpontaneousStop();
- notifyInferiorIll();
- }
-}
-
-void QmlEngine::serviceConnectionError(const QString &serviceName)
-{
- showMessage(tr("QML Debugger: Could not connect to service \"%1\".")
- .arg(serviceName), StatusBar);
-}
-
-bool QmlEngine::canDisplayTooltip() const
-{
- return false;
-}
-
-void QmlEngine::filterApplicationMessage(const QString &output, int /*channel*/)
+void QmlEngine::filterApplicationMessage(const QString &output, int /*channel*/) const
{
- m_outputParser.processOutput(output);
+ d->outputParser.processOutput(output);
}
void QmlEngine::showMessage(const QString &msg, int channel, int timeout) const
{
if (channel == AppOutput || channel == AppError)
- const_cast<QmlEngine*>(this)->filterApplicationMessage(msg, channel);
+ filterApplicationMessage(msg, channel);
DebuggerEngine::showMessage(msg, channel, timeout);
}
@@ -539,25 +487,23 @@ void QmlEngine::gotoLocation(const Location &location)
const QString fileName = location.fileName();
if (QUrl(fileName).isLocalFile()) {
// internal file from source files -> show generated .js
- QTC_ASSERT(m_sourceDocuments.contains(fileName), return);
+ QTC_ASSERT(d->sourceDocuments.contains(fileName), return);
QString titlePattern = tr("JS Source for %1").arg(fileName);
//Check if there are open documents with the same title
- foreach (Core::IDocument *document, Core::DocumentModel::openedDocuments()) {
+ foreach (IDocument *document, DocumentModel::openedDocuments()) {
if (document->displayName() == titlePattern) {
- Core::EditorManager::activateEditorForDocument(document);
+ EditorManager::activateEditorForDocument(document);
return;
}
}
- Core::IEditor *editor = Core::EditorManager::openEditorWithContents(
+ IEditor *editor = EditorManager::openEditorWithContents(
QmlJSEditor::Constants::C_QMLJSEDITOR_ID, &titlePattern);
if (editor) {
editor->document()->setProperty(Constants::OPENED_BY_DEBUGGER, true);
- QPlainTextEdit *plainTextEdit =
- qobject_cast<QPlainTextEdit *>(editor->widget());
- if (plainTextEdit)
+ if (auto plainTextEdit = qobject_cast<QPlainTextEdit *>(editor->widget()))
plainTextEdit->setReadOnly(true);
- updateDocument(editor->document(), m_sourceDocuments.value(fileName));
+ updateDocument(editor->document(), d->sourceDocuments.value(fileName));
}
} else {
DebuggerEngine::gotoLocation(location);
@@ -566,8 +512,15 @@ void QmlEngine::gotoLocation(const Location &location)
void QmlEngine::closeConnection()
{
- disconnect(watchModel(),SIGNAL(layoutChanged()),this,SLOT(synchronizeWatchers()));
- m_adapter.closeConnection();
+ disconnect(watchModel(), &QAbstractItemModel::layoutChanged,
+ this, &QmlEngine::synchronizeWatchers);
+
+ if (d->connectionTimer.isActive()) {
+ d->connectionTimer.stop();
+ } else {
+ if (d->connection)
+ d->connection->close();
+ }
}
void QmlEngine::runEngine()
@@ -576,25 +529,25 @@ void QmlEngine::runEngine()
if (!isSlaveEngine()) {
if (runParameters().startMode == AttachToRemoteServer)
- m_noDebugOutputTimer.start();
+ d->noDebugOutputTimer.start();
else if (runParameters().startMode == AttachToRemoteProcess)
beginConnection();
else
startApplicationLauncher();
} else {
- m_noDebugOutputTimer.start();
+ d->noDebugOutputTimer.start();
}
}
void QmlEngine::startApplicationLauncher()
{
- if (!m_applicationLauncher.isRunning()) {
+ if (!d->applicationLauncher.isRunning()) {
appendMessage(tr("Starting %1 %2").arg(
QDir::toNativeSeparators(runParameters().executable),
runParameters().processArgs)
+ QLatin1Char('\n')
, Utils::NormalMessageFormat);
- m_applicationLauncher.start(ProjectExplorer::ApplicationLauncher::Gui,
+ d->applicationLauncher.start(ApplicationLauncher::Gui,
runParameters().executable,
runParameters().processArgs);
}
@@ -602,10 +555,10 @@ void QmlEngine::startApplicationLauncher()
void QmlEngine::stopApplicationLauncher()
{
- if (m_applicationLauncher.isRunning()) {
- disconnect(&m_applicationLauncher, SIGNAL(processExited(int,QProcess::ExitStatus)),
- this, SLOT(disconnected()));
- m_applicationLauncher.stop();
+ if (d->applicationLauncher.isRunning()) {
+ disconnect(&d->applicationLauncher, &ApplicationLauncher::processExited,
+ this, &QmlEngine::disconnected);
+ d->applicationLauncher.stop();
}
}
@@ -622,12 +575,12 @@ void QmlEngine::notifyEngineRemoteSetupFinished(const RemoteSetupResult &result)
// The remote setup can take while especialy with mixed debugging.
// Just waiting for 8 seconds is not enough. Increase the timeout
// to 60 s
- // In case we get an output the m_outputParser will start the connection.
- m_noDebugOutputTimer.setInterval(60000);
+ // In case we get an output the d->outputParser will start the connection.
+ d->noDebugOutputTimer.setInterval(60000);
}
else {
if (isMasterEngine())
- QMessageBox::critical(Core::ICore::dialogParent(), tr("Failed to start application"),
+ QMessageBox::critical(ICore::dialogParent(), tr("Failed to start application"),
tr("Application startup failed: %1").arg(result.reason));
notifyEngineSetupFailed();
}
@@ -646,16 +599,15 @@ void QmlEngine::notifyEngineRemoteServerRunning(const QByteArray &serverChannel,
notifyEngineSetupOk();
// The remote setup can take a while especially with mixed debugging.
- // Just waiting for 8 seconds is not enough. Increase the timeout
- // to 60 s
- // In case we get an output the m_outputParser will start the connection.
- m_noDebugOutputTimer.setInterval(60000);
+ // Just waiting for 8 seconds is not enough. Increase the timeout to 60 s.
+ // In case we get an output the d->outputParser will start the connection.
+ d->noDebugOutputTimer.setInterval(60000);
}
void QmlEngine::shutdownInferior()
{
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->endSession();
+ // End session.
+ d->disconnect();
if (isSlaveEngine())
resetLocation();
@@ -667,12 +619,11 @@ void QmlEngine::shutdownInferior()
void QmlEngine::shutdownEngine()
{
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->resetSession();
+ clearExceptionSelection();
- if (qmlConsoleManager())
- qmlConsoleManager()->setScriptEvaluator(0);
- m_noDebugOutputTimer.stop();
+ if (auto consoleManager = ConsoleManagerInterface::instance())
+ consoleManager->setScriptEvaluator(0);
+ d->noDebugOutputTimer.stop();
// double check (ill engine?):
stopApplicationLauncher();
@@ -688,12 +639,12 @@ void QmlEngine::setupEngine()
// we need to get the port first
notifyEngineRequestRemoteSetup();
} else {
- m_applicationLauncher.setEnvironment(runParameters().environment);
- m_applicationLauncher.setWorkingDirectory(runParameters().workingDirectory);
+ d->applicationLauncher.setEnvironment(runParameters().environment);
+ d->applicationLauncher.setWorkingDirectory(runParameters().workingDirectory);
// We can't do this in the constructore because runControl() isn't yet defined
- connect(&m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
- runControl(), SLOT(bringApplicationToForeground(qint64)),
+ connect(&d->applicationLauncher, &ApplicationLauncher::bringToForegroundRequested,
+ runControl(), &RunControl::bringApplicationToForeground,
Qt::UniqueConnection);
notifyEngineSetupOk();
@@ -703,8 +654,8 @@ void QmlEngine::setupEngine()
void QmlEngine::continueInferior()
{
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->continueInferior();
+ clearExceptionSelection();
+ d->continueDebugging(Continue);
resetLocation();
notifyInferiorRunRequested();
notifyInferiorRunOk();
@@ -712,39 +663,39 @@ void QmlEngine::continueInferior()
void QmlEngine::interruptInferior()
{
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->interruptInferior();
+ showMessage(_(INTERRUPT), LogInput);
+ d->sendMessage(d->packMessage(INTERRUPT));
notifyInferiorStopOk();
}
void QmlEngine::executeStep()
{
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->executeStep();
+ clearExceptionSelection();
+ d->continueDebugging(StepIn);
notifyInferiorRunRequested();
notifyInferiorRunOk();
}
void QmlEngine::executeStepI()
{
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->executeStepI();
+ clearExceptionSelection();
+ d->continueDebugging(StepIn);
notifyInferiorRunRequested();
notifyInferiorRunOk();
}
void QmlEngine::executeStepOut()
{
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->executeStepOut();
+ clearExceptionSelection();
+ d->continueDebugging(StepOut);
notifyInferiorRunRequested();
notifyInferiorRunOk();
}
void QmlEngine::executeNext()
{
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->executeNext();
+ clearExceptionSelection();
+ d->continueDebugging(Next);
notifyInferiorRunRequested();
notifyInferiorRunOk();
}
@@ -765,8 +716,11 @@ void QmlEngine::executeRunToLine(const ContextData &data)
bool valid;
if (adjustBreakpointLineAndColumn(data.fileName, &line, &column, &valid))
modifiedData.lineNumber = line;
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->executeRunToLine(modifiedData);
+ d->setBreakpoint(QString(_(SCRIPTREGEXP)), modifiedData.fileName,
+ true, modifiedData.lineNumber);
+ clearExceptionSelection();
+ d->continueDebugging(Continue);
+
notifyInferiorRunRequested();
notifyInferiorRunOk();
}
@@ -788,8 +742,10 @@ void QmlEngine::activateFrame(int index)
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
return;
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->activateFrame(index);
+ if (index != stackHandler()->currentIndex())
+ d->frame(d->stackIndexLookup.value(index));
+
+ stackHandler()->setCurrentIndex(index);
gotoLocation(stackHandler()->frames().value(index));
}
@@ -811,31 +767,39 @@ void QmlEngine::insertBreakpoint(Breakpoint bp)
bool valid = false;
if (!adjustBreakpointLineAndColumn(params.fileName, &line, &column,
&valid)) {
- pendingBreakpoints.insertMulti(params.fileName, bp);
+ d->pendingBreakpoints.insertMulti(params.fileName, bp);
return;
}
if (!valid)
return;
}
- if (m_adapter.activeDebuggerClient()) {
- m_adapter.activeDebuggerClient()->insertBreakpoint(bp, line, column);
- } else {
- foreach (BaseQmlDebuggerClient *client, m_adapter.debuggerClients()) {
- client->insertBreakpoint(bp, line, column);
- }
+ if (params.type == BreakpointAtJavaScriptThrow) {
+ bp.notifyBreakpointInsertOk();
+ d->setExceptionBreak(AllExceptions, params.enabled);
+
+ } else if (params.type == BreakpointByFileAndLine) {
+ d->setBreakpoint(QString(_(SCRIPTREGEXP)), params.fileName,
+ params.enabled, line, column,
+ QLatin1String(params.condition), params.ignoreCount);
+
+ } else if (params.type == BreakpointOnQmlSignalEmit) {
+ d->setBreakpoint(QString(_(EVENT)), params.functionName, params.enabled);
+ bp.notifyBreakpointInsertOk();
}
+
+ d->breakpointsSync.insert(d->sequence, bp.id());
}
void QmlEngine::removeBreakpoint(Breakpoint bp)
{
const BreakpointParameters &params = bp.parameters();
if (params.type == BreakpointByFileAndLine &&
- pendingBreakpoints.contains(params.fileName)) {
- auto it = pendingBreakpoints.find(params.fileName);
- while (it != pendingBreakpoints.end() && it.key() == params.fileName) {
+ d->pendingBreakpoints.contains(params.fileName)) {
+ auto it = d->pendingBreakpoints.find(params.fileName);
+ while (it != d->pendingBreakpoints.end() && it.key() == params.fileName) {
if (it.value() == bp.id()) {
- pendingBreakpoints.erase(it);
+ d->pendingBreakpoints.erase(it);
return;
}
++it;
@@ -846,13 +810,15 @@ void QmlEngine::removeBreakpoint(Breakpoint bp)
QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << bp << this << state);
bp.notifyBreakpointRemoveProceeding();
- if (m_adapter.activeDebuggerClient()) {
- m_adapter.activeDebuggerClient()->removeBreakpoint(bp);
- } else {
- foreach (BaseQmlDebuggerClient *client, m_adapter.debuggerClients()) {
- client->removeBreakpoint(bp);
- }
- }
+ int breakpoint = d->breakpoints.value(bp.id());
+ d->breakpoints.remove(bp.id());
+
+ if (params.type == BreakpointAtJavaScriptThrow)
+ d->setExceptionBreak(AllExceptions);
+ else if (params.type == BreakpointOnQmlSignalEmit)
+ d->setBreakpoint(QString(_(EVENT)), params.functionName, false);
+ else
+ d->clearBreakpoint(breakpoint);
if (bp.state() == BreakpointRemoveProceeding)
bp.notifyBreakpointRemoveOk();
@@ -864,12 +830,24 @@ void QmlEngine::changeBreakpoint(Breakpoint bp)
QTC_ASSERT(state == BreakpointChangeRequested, qDebug() << bp << this << state);
bp.notifyBreakpointChangeProceeding();
- if (m_adapter.activeDebuggerClient()) {
- m_adapter.activeDebuggerClient()->changeBreakpoint(bp);
+ const BreakpointParameters &params = bp.parameters();
+
+ BreakpointResponse br = bp.response();
+ if (params.type == BreakpointAtJavaScriptThrow) {
+ d->setExceptionBreak(AllExceptions, params.enabled);
+ br.enabled = params.enabled;
+ bp.setResponse(br);
+ } else if (params.type == BreakpointOnQmlSignalEmit) {
+ d->setBreakpoint(QString(_(EVENT)), params.functionName, params.enabled);
+ br.enabled = params.enabled;
+ bp.setResponse(br);
} else {
- foreach (BaseQmlDebuggerClient *client, m_adapter.debuggerClients()) {
- client->changeBreakpoint(bp);
- }
+ //V8 supports only minimalistic changes in breakpoint
+ //Remove the breakpoint and add again
+ bp.notifyBreakpointChangeOk();
+ bp.removeBreakpoint();
+ BreakHandler *handler = d->engine->breakHandler();
+ handler->appendBreakpoint(params);
}
if (bp.state() == BreakpointChangeProceeding)
@@ -918,14 +896,6 @@ void QmlEngine::attemptBreakpointSynchronization()
}
DebuggerEngine::attemptBreakpointSynchronization();
-
- if (m_adapter.activeDebuggerClient()) {
- m_adapter.activeDebuggerClient()->synchronizeBreakpoints();
- } else {
- foreach (BaseQmlDebuggerClient *client, m_adapter.debuggerClients()) {
- client->synchronizeBreakpoints();
- }
- }
}
bool QmlEngine::acceptsBreakpoint(Breakpoint bp) const
@@ -937,10 +907,10 @@ bool QmlEngine::acceptsBreakpoint(Breakpoint bp) const
//TODO: enable setting of breakpoints before start of debug session
//For now, the event breakpoint can be set after the activeDebuggerClient is known
//This is because the older client does not support BreakpointOnQmlSignalHandler
- bool acceptBreakpoint = false;
- if (m_adapter.activeDebuggerClient())
- acceptBreakpoint = m_adapter.activeDebuggerClient()->acceptsBreakpoint(bp);
- return acceptBreakpoint;
+ BreakpointType type = bp.type();
+ return type == BreakpointOnQmlSignalEmit
+ || type == BreakpointByFileAndLine
+ || type == BreakpointAtJavaScriptThrow;
}
void QmlEngine::loadSymbols(const QString &moduleName)
@@ -958,8 +928,7 @@ void QmlEngine::reloadModules()
void QmlEngine::reloadSourceFiles()
{
- if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->getSourceFiles();
+ d->scripts(4, QList<int>(), true, QVariant());
}
void QmlEngine::requestModuleSymbols(const QString &moduleName)
@@ -967,12 +936,6 @@ void QmlEngine::requestModuleSymbols(const QString &moduleName)
Q_UNUSED(moduleName)
}
-//////////////////////////////////////////////////////////////////////
-//
-// Tooltip specific stuff
-//
-//////////////////////////////////////////////////////////////////////
-
bool QmlEngine::canHandleToolTip(const DebuggerToolTipContext &) const
{
// This is processed by QML inspector, which has dependencies to
@@ -981,20 +944,23 @@ bool QmlEngine::canHandleToolTip(const DebuggerToolTipContext &) const
return true;
}
-//////////////////////////////////////////////////////////////////////
-//
-// Watch specific stuff
-//
-//////////////////////////////////////////////////////////////////////
-
void QmlEngine::assignValueInDebugger(WatchItem *item,
const QString &expression, const QVariant &valueV)
{
if (!expression.isEmpty()) {
- if (item->isInspect() && m_inspectorAdapter.agent())
- m_inspectorAdapter.agent()->assignValue(item, expression, valueV);
- else if (m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->assignValueInDebugger(item, expression, valueV);
+ if (item->isInspect() && d->inspectorAdapter.agent()) {
+ d->inspectorAdapter.agent()->assignValue(item, expression, valueV);
+ } else {
+ StackHandler *handler = stackHandler();
+ QString expression = QString(_("%1 = %2;")).arg(expression).arg(valueV.toString());
+ if (handler->isContentsValid() && handler->currentFrame().isUsable()) {
+ d->evaluate(expression, false, false, handler->currentIndex());
+ d->updateLocalsAndWatchers.append(d->sequence);
+ } else {
+ showMessage(QString(_("Cannot evaluate %1 in current stack frame")).arg(
+ expression), ConsoleOutput);
+ }
+ }
}
}
@@ -1008,14 +974,11 @@ void QmlEngine::updateWatchData(const QByteArray &iname)
return;
if (item->isInspect()) {
- m_inspectorAdapter.agent()->updateWatchData(*item);
+ d->inspectorAdapter.agent()->updateWatchData(*item);
} else {
- if (!item->name.isEmpty() && m_adapter.activeDebuggerClient()) {
- if (item->isValueNeeded())
- m_adapter.activeDebuggerClient()->updateWatchData(*item);
- if (item->isChildrenNeeded() && watchHandler()->isExpandedIName(item->iname)) {
- m_adapter.activeDebuggerClient()->expandObject(item->iname, item->id);
- }
+ if (!item->name.isEmpty()) {
+ if (item->isChildrenNeeded() && watchHandler()->isExpandedIName(item->iname))
+ d->expandObject(item->iname, item->id);
}
synchronizeWatchers();
}
@@ -1025,26 +988,30 @@ void QmlEngine::selectWatchData(const QByteArray &iname)
{
const WatchItem *item = watchHandler()->findItem(iname);
if (item && item->isInspect())
- m_inspectorAdapter.agent()->watchDataSelected(item->id);
+ d->inspectorAdapter.agent()->watchDataSelected(item->id);
}
void QmlEngine::synchronizeWatchers()
{
- QStringList watchedExpressions = watchHandler()->watchedExpressions();
+ if (state() != InferiorStopOk)
+ return;
+
+ QStringList watchers = watchHandler()->watchedExpressions();
+
// send watchers list
- if (m_adapter.activeDebuggerClient()) {
- m_adapter.activeDebuggerClient()->synchronizeWatchers(watchedExpressions);
- } else {
- foreach (BaseQmlDebuggerClient *client, m_adapter.debuggerClients())
- client->synchronizeWatchers(watchedExpressions);
+ foreach (const QString &exp, watchers) {
+ StackHandler *handler = stackHandler();
+ if (handler->isContentsValid() && handler->currentFrame().isUsable()) {
+ d->evaluate(exp, false, false, handler->currentIndex());
+ d->evaluatingExpression.insert(d->sequence, exp);
+ }
}
}
-ConsoleItem *constructLogItemTree(ConsoleItem *parent,
- const QVariant &result,
- const QString &key = QString())
+static ConsoleItem *constructLogItemTree(ConsoleItem *parent,
+ const QVariant &result,
+ const QString &key = QString())
{
- using namespace QmlJS;
bool sorted = boolSetting(SortStructMembers);
if (!result.isValid())
return 0;
@@ -1086,13 +1053,10 @@ ConsoleItem *constructLogItemTree(ConsoleItem *parent,
void QmlEngine::expressionEvaluated(quint32 queryId, const QVariant &result)
{
- if (queryIds.contains(queryId)) {
- queryIds.removeOne(queryId);
- using namespace QmlJS;
- ConsoleManagerInterface *consoleManager = qmlConsoleManager();
- if (consoleManager) {
- ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), result);
- if (item)
+ if (d->queryIds.contains(queryId)) {
+ d->queryIds.removeOne(queryId);
+ if (auto consoleManager = ConsoleManagerInterface::instance()) {
+ if (ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), result))
consoleManager->printToConsolePane(item);
}
}
@@ -1116,18 +1080,12 @@ bool QmlEngine::hasCapability(unsigned cap) const
void QmlEngine::quitDebugger()
{
- m_noDebugOutputTimer.stop();
- m_automaticConnect = false;
- m_retryOnConnectFail = false;
+ d->noDebugOutputTimer.stop();
+ d->automaticConnect = false;
+ d->retryOnConnectFail = false;
DebuggerEngine::quitDebugger();
}
-void QmlEngine::inferiorSpontaneousStop()
-{
- if (state() == InferiorRunOk)
- notifyInferiorSpontaneousStop();
-}
-
void QmlEngine::disconnected()
{
showMessage(tr("QML Debugger disconnected."), StatusBar);
@@ -1137,9 +1095,9 @@ void QmlEngine::disconnected()
void QmlEngine::documentUpdated(Document::Ptr doc)
{
QString fileName = doc->fileName();
- if (pendingBreakpoints.contains(fileName)) {
- QList<Breakpoint> bps = pendingBreakpoints.values(fileName);
- pendingBreakpoints.remove(fileName);
+ if (d->pendingBreakpoints.contains(fileName)) {
+ QList<Breakpoint> bps = d->pendingBreakpoints.values(fileName);
+ d->pendingBreakpoints.remove(fileName);
foreach (const Breakpoint bp, bps)
insertBreakpoint(bp);
}
@@ -1151,13 +1109,12 @@ void QmlEngine::updateCurrentContext()
if (state() == InferiorStopOk) {
context = stackHandler()->currentFrame().function;
} else {
- QModelIndex currentIndex = inspectorTreeView()->currentIndex();
+ QModelIndex currentIndex = inspectorView()->currentIndex();
const WatchData *currentData = watchHandler()->watchItem(currentIndex);
if (!currentData)
return;
const WatchData *parentData = watchHandler()->watchItem(currentIndex.parent());
- const WatchData *grandParentData = watchHandler()->watchItem(
- currentIndex.parent().parent());
+ const WatchData *grandParentData = watchHandler()->watchItem(currentIndex.parent().parent());
if (currentData->id != parentData->id)
context = currentData->name;
else if (parentData->id != grandParentData->id)
@@ -1168,44 +1125,24 @@ void QmlEngine::updateCurrentContext()
synchronizeWatchers();
- ConsoleManagerInterface *consoleManager = qmlConsoleManager();
- if (consoleManager)
+ if (auto consoleManager = ConsoleManagerInterface::instance())
consoleManager->setContext(tr("Context:") + QLatin1Char(' ') + context);
}
-void QmlEngine::appendDebugOutput(QtMsgType type, const QString &message,
- const QmlDebug::QDebugContextInfo &info)
+void QmlEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
{
- using namespace QmlJS;
- ConsoleItem::ItemType itemType;
- switch (type) {
- case QtDebugMsg:
- itemType = ConsoleItem::DebugType;
- break;
- case QtWarningMsg:
- itemType = ConsoleItem::WarningType;
- break;
- case QtCriticalMsg:
- case QtFatalMsg:
- itemType = ConsoleItem::ErrorType;
- break;
- default:
- //This case is not possible
+ if (!(languages & QmlLanguage))
return;
- }
- ConsoleManagerInterface *consoleManager = qmlConsoleManager();
- if (consoleManager) {
- ConsoleItem *item = new ConsoleItem(consoleManager->rootItem(), itemType, message);
- item->file = info.file;
- item->line = info.line;
- consoleManager->printToConsolePane(item);
- }
-}
-void QmlEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
-{
- if ((languages & QmlLanguage) && m_adapter.activeDebuggerClient())
- m_adapter.activeDebuggerClient()->executeDebuggerCommand(command);
+ StackHandler *handler = stackHandler();
+ if (handler->isContentsValid() && handler->currentFrame().isUsable()) {
+ d->evaluate(command, false, false, handler->currentIndex());
+ d->debuggerCommands.append(d->sequence);
+ } else {
+ //Currently cannot evaluate if not in a javascript break
+ d->engine->showMessage(QString(_("Cannot evaluate %1 in current stack frame")).arg(
+ command), ConsoleOutput);
+ }
}
bool QmlEngine::evaluateScript(const QString &expression)
@@ -1214,17 +1151,15 @@ bool QmlEngine::evaluateScript(const QString &expression)
// Evaluate expression based on engine state
// When engine->state() == InferiorStopOk, the expression is sent to debuggerClient.
if (state() != InferiorStopOk) {
- QModelIndex currentIndex = inspectorTreeView()->currentIndex();
- QmlInspectorAgent *agent = m_inspectorAdapter.agent();
+ QModelIndex currentIndex = inspectorView()->currentIndex();
+ QmlInspectorAgent *agent = d->inspectorAdapter.agent();
quint32 queryId = agent->queryExpressionResult(watchHandler()->watchItem(currentIndex)->id,
expression);
if (queryId) {
- queryIds << queryId;
+ d->queryIds.append(queryId);
} else {
didEvaluate = false;
- using namespace QmlJS;
- ConsoleManagerInterface *consoleManager = qmlConsoleManager();
- if (consoleManager) {
+ if (auto consoleManager = ConsoleManagerInterface::instance()) {
consoleManager->printToConsolePane(ConsoleItem::ErrorType,
_("Error evaluating expression."));
}
@@ -1235,42 +1170,15 @@ bool QmlEngine::evaluateScript(const QString &expression)
return didEvaluate;
}
-QString QmlEngine::qmlImportPath() const
-{
- return runParameters().environment.value(QLatin1String("QML_IMPORT_PATH"));
-}
-
-void QmlEngine::logMessage(const QString &service, LogDirection direction, const QString &message)
-{
- QString msg = service;
- msg += direction == LogSend ? QLatin1String(": sending ") : QLatin1String(": receiving ");
- msg += message;
- showMessage(msg, LogDebug);
-}
-
-void QmlEngine::setSourceFiles(const QStringList &fileNames)
-{
- QMap<QString,QString> files;
- foreach (const QString &file, fileNames) {
- QString shortName = file;
- QString fullName = toFileInProject(file);
- files.insert(shortName, fullName);
- }
-
- sourceFilesHandler()->setSourceFiles(files);
- //update open editors
-
-}
-
-void QmlEngine::updateScriptSource(const QString &fileName, int lineOffset, int columnOffset,
- const QString &source)
+void QmlEnginePrivate::updateScriptSource(const QString &fileName, int lineOffset, int columnOffset,
+ const QString &source)
{
QTextDocument *document = 0;
- if (m_sourceDocuments.contains(fileName)) {
- document = m_sourceDocuments.value(fileName);
+ if (sourceDocuments.contains(fileName)) {
+ document = sourceDocuments.value(fileName);
} else {
document = new QTextDocument(this);
- m_sourceDocuments.insert(fileName, document);
+ sourceDocuments.insert(fileName, document);
}
// We're getting an unordered set of snippets that can even interleave
@@ -1307,7 +1215,7 @@ void QmlEngine::updateScriptSource(const QString &fileName, int lineOffset, int
//update open editors
QString titlePattern = tr("JS Source for %1").arg(fileName);
//Check if there are open editors with the same title
- foreach (Core::IDocument *doc, Core::DocumentModel::openedDocuments()) {
+ foreach (IDocument *doc, DocumentModel::openedDocuments()) {
if (doc->displayName() == titlePattern) {
updateDocument(doc, document);
break;
@@ -1315,45 +1223,1446 @@ void QmlEngine::updateScriptSource(const QString &fileName, int lineOffset, int
}
}
-void QmlEngine::updateDocument(Core::IDocument *document, const QTextDocument *textDocument)
+bool QmlEnginePrivate::canEvaluateScript(const QString &script)
+{
+ interpreter.clearText();
+ interpreter.appendText(script);
+ return interpreter.canEvaluate();
+}
+
+void QmlEngine::connectionErrorOccurred(QDebugSupport::Error error)
+{
+ // this is only an error if we are already connected and something goes wrong.
+ if (isConnected()) {
+ if (error == QDebugSupport::RemoteClosedConnectionError)
+ showMessage(tr("QML Debugger: Remote host closed connection."), StatusBar);
+
+ if (!isSlaveEngine()) { // normal flow for slave engine when gdb exits
+ notifyInferiorSpontaneousStop();
+ notifyInferiorIll();
+ }
+ } else {
+ d->connectionTimer.stop();
+ connectionStartupFailed();
+ }
+}
+
+void QmlEngine::clientStateChanged(QmlDebugClient::State state)
+{
+ QString serviceName;
+ float version = 0;
+ if (QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender())) {
+ serviceName = client->name();
+ version = client->remoteVersion();
+ }
+
+ logServiceStateChange(serviceName, version, state);
+}
+
+void QmlEngine::checkConnectionState()
+{
+ if (!isConnected()) {
+ closeConnection();
+ connectionStartupFailed();
+ }
+}
+
+bool QmlEngine::isConnected() const
+{
+ return d->connection->isOpen();
+}
+
+void QmlEngine::showConnectionStateMessage(const QString &message)
+{
+ showMessage(_("QML Debugger: ") + message, LogStatus);
+}
+
+void QmlEngine::showConnectionErrorMessage(const QString &message)
+{
+ showMessage(_("QML Debugger: ") + message, LogError);
+}
+
+void QmlEngine::logServiceStateChange(const QString &service, float version,
+ QmlDebugClient::State newState)
+{
+ switch (newState) {
+ case QmlDebugClient::Unavailable: {
+ showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'unavailable'.").
+ arg(service).arg(QString::number(version)));
+ break;
+ }
+ case QmlDebugClient::Enabled: {
+ showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'enabled'.").
+ arg(service).arg(QString::number(version)));
+ break;
+ }
+
+ case QmlDebugClient::NotConnected: {
+ showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'not connected'.").
+ arg(service).arg(QString::number(version)));
+ break;
+ }
+ }
+}
+
+void QmlEngine::logServiceActivity(const QString &service, const QString &logMessage)
+{
+ showMessage(service + QLatin1Char(' ') + logMessage, LogDebug);
+}
+
+void QmlEnginePrivate::connect()
+{
+ engine->showMessage(_(CONNECT), LogInput);
+ sendMessage(packMessage(CONNECT));
+}
+
+void QmlEnginePrivate::disconnect()
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "disconnect",
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(DISCONNECT));
+
+ const QByteArray msg = QJsonDocument(jsonVal).toJson(QJsonDocument::Compact);
+ engine->showMessage(QString::fromUtf8(msg), LogInput);
+ sendMessage(packMessage(DISCONNECT, msg));
+}
+
+void QmlEnginePrivate::continueDebugging(StepAction action)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "continue",
+ // "arguments" : { "stepaction" : <"in", "next" or "out">,
+ // "stepcount" : <number of steps (default 1)>
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(CONTINEDEBUGGING));
+
+ if (action != Continue) {
+ QJsonObject args;
+ switch (action) {
+ case StepIn:
+ args.insert(_(STEPACTION), _(IN));
+ break;
+ case StepOut:
+ args.insert(_(STEPACTION), _(OUT));
+ break;
+ case Next:
+ args.insert(_(STEPACTION), _(NEXT));
+ break;
+ default:break;
+ }
+
+ jsonVal.insert(_(ARGUMENTS), args);
+ }
+ sendAndLogV8Request(jsonVal);
+ previousStepAction = action;
+}
+
+void QmlEnginePrivate::evaluate(const QString expr, bool global,
+ bool disableBreak, int frame, bool addContext)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "evaluate",
+ // "arguments" : { "expression" : <expression to evaluate>,
+ // "frame" : <number>,
+ // "global" : <boolean>,
+ // "disable_break" : <boolean>,
+ // "additional_context" : [
+ // { "name" : <name1>, "handle" : <handle1> },
+ // { "name" : <name2>, "handle" : <handle2> },
+ // ...
+ // ]
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(EVALUATE));
+
+ QJsonObject args {
+ { _(EXPRESSION), expr }
+ };
+
+ if (frame != -1)
+ args.insert(_(FRAME), frame);
+
+ if (global)
+ args.insert(_(GLOBAL), global);
+
+ if (disableBreak)
+ args.insert(_(DISABLE_BREAK), disableBreak);
+
+ if (addContext) {
+ WatchHandler *watchHandler = engine->watchHandler();
+ QAbstractItemModel *watchModel = watchHandler->model();
+ int rowCount = watchModel->rowCount();
+
+ QJsonArray ctxtList;
+ while (rowCount) {
+ QModelIndex index = watchModel->index(--rowCount, 0);
+ const WatchData *data = watchHandler->watchItem(index);
+ const QJsonObject ctxt {
+ { _(NAME), data->name },
+ { _(HANDLE), int(data->id) }
+ };
+
+ ctxtList.push_front(ctxt);
+ }
+
+ args.insert(_(ADDITIONAL_CONTEXT), ctxtList);
+ }
+
+ jsonVal.insert(_(ARGUMENTS), args);
+
+ sendAndLogV8Request(jsonVal);
+}
+
+void QmlEnginePrivate::lookup(QList<int> handles, bool includeSource)
{
- TextEditor::TextDocument *baseTextDocument
- = qobject_cast<TextEditor::TextDocument *>(document);
- if (!baseTextDocument)
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "lookup",
+ // "arguments" : { "handles" : <array of handles>,
+ // "includeSource" : <boolean indicating whether
+ // the source will be included when
+ // script objects are returned>,
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(LOOKUP));
+
+ QJsonObject args;
+
+ QJsonArray array;
+ foreach (int handle, handles)
+ array.push_back(handle);
+ args.insert(_(HANDLES), array);
+
+ if (includeSource)
+ args.insert(_(INCLUDESOURCE), includeSource);
+
+ jsonVal.insert(_(ARGUMENTS), args);
+
+ sendAndLogV8Request(jsonVal);
+}
+
+void QmlEnginePrivate::backtrace(int fromFrame, int toFrame, bool bottom)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "backtrace",
+ // "arguments" : { "fromFrame" : <number>
+ // "toFrame" : <number>
+ // "bottom" : <boolean, set to true if the bottom of the
+ // stack is requested>
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(BACKTRACE));
+
+ QJsonObject args;
+
+ if (fromFrame != -1)
+ args.insert(_(FROMFRAME), fromFrame);
+
+ if (toFrame != -1)
+ args.insert(_(TOFRAME), toFrame);
+
+ if (bottom)
+ args.insert(_(BOTTOM), bottom);
+
+ jsonVal.insert(_(ARGUMENTS), args);
+
+ sendAndLogV8Request(jsonVal);
+}
+
+void QmlEnginePrivate::frame(int number)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "frame",
+ // "arguments" : { "number" : <frame number>
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(FRAME));
+
+ if (number != -1) {
+ const QJsonObject args {
+ { _(NUMBER), number }
+ };
+
+ jsonVal.insert(_(ARGUMENTS), args);
+ }
+
+ sendAndLogV8Request(jsonVal);
+}
+
+void QmlEnginePrivate::scope(int number, int frameNumber)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "scope",
+ // "arguments" : { "number" : <scope number>
+ // "frameNumber" : <frame number, optional uses selected
+ // frame if missing>
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(SCOPE));
+
+ if (number != -1) {
+ QJsonObject args {
+ { _(NUMBER), number }
+ };
+
+ if (frameNumber != -1)
+ args.insert(_(FRAMENUMBER), frameNumber);
+
+ jsonVal.insert(_(ARGUMENTS), args);
+ }
+
+ sendAndLogV8Request(jsonVal);
+}
+
+void QmlEnginePrivate::scripts(int types, const QList<int> ids, bool includeSource,
+ const QVariant filter)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "scripts",
+ // "arguments" : { "types" : <types of scripts to retrieve
+ // set bit 0 for native scripts
+ // set bit 1 for extension scripts
+ // set bit 2 for normal scripts
+ // (default is 4 for normal scripts)>
+ // "ids" : <array of id's of scripts to return. If this is not specified all scripts are requrned>
+ // "includeSource" : <boolean indicating whether the source code should be included for the scripts returned>
+ // "filter" : <string or number: filter string or script id.
+ // If a number is specified, then only the script with the same number as its script id will be retrieved.
+ // If a string is specified, then only scripts whose names contain the filter string will be retrieved.>
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(SCRIPTS));
+
+ QJsonObject args {
+ { _(TYPES), types }
+ };
+
+ if (ids.count()) {
+ QJsonArray array;
+ foreach (int id, ids) {
+ array.push_back(id);
+ }
+ args.insert(_(IDS), array);
+ }
+
+ if (includeSource)
+ args.insert(_(INCLUDESOURCE), includeSource);
+
+ QJsonValue filterValue;
+ if (filter.type() == QVariant::String)
+ filterValue = filter.toString();
+ else if (filter.type() == QVariant::Int)
+ filterValue = filter.toInt();
+ else
+ QTC_CHECK(!filter.isValid());
+
+ args.insert(_(FILTER), filterValue);
+
+ jsonVal.insert(_(ARGUMENTS), args);
+
+ sendAndLogV8Request(jsonVal);
+}
+
+void QmlEnginePrivate::setBreakpoint(const QString type, const QString target,
+ bool enabled, int line, int column,
+ const QString condition, int ignoreCount)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "setbreakpoint",
+ // "arguments" : { "type" : <"function" or "script" or "scriptId" or "scriptRegExp">
+ // "target" : <function expression or script identification>
+ // "line" : <line in script or function>
+ // "column" : <character position within the line>
+ // "enabled" : <initial enabled state. True or false, default is true>
+ // "condition" : <string with break point condition>
+ // "ignoreCount" : <number specifying the number of break point hits to ignore, default value is 0>
+ // }
+ // }
+ if (type == _(EVENT)) {
+ QByteArray params;
+ QmlDebugStream rs(&params, QIODevice::WriteOnly);
+ rs << target.toUtf8() << enabled;
+ engine->showMessage(QString(_("%1 %2 %3")).arg(_(BREAKONSIGNAL), target, enabled ? _("enabled") : _("disabled")), LogInput);
+ sendMessage(packMessage(BREAKONSIGNAL, params));
+
+ } else {
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(SETBREAKPOINT));
+
+ QJsonObject args {
+ { _(TYPE), type },
+ { _(ENABLED), enabled }
+ };
+ if (type == _(SCRIPTREGEXP))
+ args.insert(_(TARGET), Utils::FileName::fromString(target).fileName());
+ else
+ args.insert(_(TARGET), target);
+
+ if (line)
+ args.insert(_(LINE), line - 1);
+
+ if (column)
+ args.insert(_(COLUMN), column - 1);
+
+ if (!condition.isEmpty())
+ args.insert(_(CONDITION), condition);
+
+ if (ignoreCount != -1)
+ args.insert(_(IGNORECOUNT), ignoreCount);
+
+ jsonVal.insert(_(ARGUMENTS), args);
+
+ sendAndLogV8Request(jsonVal);
+ }
+}
+
+void QmlEnginePrivate::clearBreakpoint(int breakpoint)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "clearbreakpoint",
+ // "arguments" : { "breakpoint" : <number of the break point to clear>
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(CLEARBREAKPOINT));
+
+ QJsonObject args {
+ { _(BREAKPOINT), breakpoint }
+ };
+
+ jsonVal.insert(_(ARGUMENTS), args);
+
+ sendAndLogV8Request(jsonVal);
+}
+
+void QmlEnginePrivate::setExceptionBreak(Exceptions type, bool enabled)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "setexceptionbreak",
+ // "arguments" : { "type" : <string: "all", or "uncaught">,
+ // "enabled" : <optional bool: enables the break type if true>
+ // }
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(SETEXCEPTIONBREAK));
+
+ QJsonObject args;
+
+ if (type == AllExceptions)
+ args.insert(_(TYPE), _(ALL));
+ //Not Supported
+ // else if (type == UncaughtExceptions)
+ // args.setProperty(_(TYPE),QScriptValue(_(UNCAUGHT)));
+
+ if (enabled)
+ args.insert(_(ENABLED), enabled);
+
+ jsonVal.insert(_(ARGUMENTS), args);
+
+ sendAndLogV8Request(jsonVal);
+}
+
+void QmlEnginePrivate::version()
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "version",
+ // }
+ QJsonObject jsonVal = initObject();
+ jsonVal.insert(_(COMMAND), _(VERSION));
+
+ sendAndLogV8Request(jsonVal);
+}
+
+QVariant valueFromRef(int handle, const QVariant &refsVal, bool *success)
+{
+ *success = false;
+ QVariant variant;
+ const QVariantList refs = refsVal.toList();
+ foreach (const QVariant &ref, refs) {
+ const QVariantMap refData = ref.toMap();
+ if (refData.value(_(HANDLE)).toInt() == handle) {
+ variant = refData;
+ *success = true;
+ break;
+ }
+ }
+ return variant;
+}
+
+QmlV8ObjectData extractData(const QVariant &data, const QVariant &refsVal)
+{
+ // { "handle" : <handle>,
+ // "type" : <"undefined", "null", "boolean", "number", "string", "object", "function" or "frame">
+ // }
+
+ // {"handle":<handle>,"type":"undefined"}
+
+ // {"handle":<handle>,"type":"null"}
+
+ // { "handle":<handle>,
+ // "type" : <"boolean", "number" or "string">
+ // "value" : <JSON encoded value>
+ // }
+
+ // {"handle":7,"type":"boolean","value":true}
+
+ // {"handle":8,"type":"number","value":42}
+
+ // { "handle" : <handle>,
+ // "type" : "object",
+ // "className" : <Class name, ECMA-262 property [[Class]]>,
+ // "constructorFunction" : {"ref":<handle>},
+ // "protoObject" : {"ref":<handle>},
+ // "prototypeObject" : {"ref":<handle>},
+ // "properties" : [ {"name" : <name>,
+ // "ref" : <handle>
+ // },
+ // ...
+ // ]
+ // }
+
+ // { "handle" : <handle>,
+ // "type" : "function",
+ // "className" : "Function",
+ // "constructorFunction" : {"ref":<handle>},
+ // "protoObject" : {"ref":<handle>},
+ // "prototypeObject" : {"ref":<handle>},
+ // "name" : <function name>,
+ // "inferredName" : <inferred function name for anonymous functions>
+ // "source" : <function source>,
+ // "script" : <reference to function script>,
+ // "scriptId" : <id of function script>,
+ // "position" : <function begin position in script>,
+ // "line" : <function begin source line in script>,
+ // "column" : <function begin source column in script>,
+ // "properties" : [ {"name" : <name>,
+ // "ref" : <handle>
+ // },
+ // ...
+ // ]
+ // }
+
+ QmlV8ObjectData objectData;
+ const QVariantMap dataMap = data.toMap();
+
+ objectData.name = dataMap.value(_(NAME)).toByteArray();
+
+ if (dataMap.contains(_(REF))) {
+ objectData.handle = dataMap.value(_(REF)).toInt();
+ bool success;
+ QVariant dataFromRef = valueFromRef(objectData.handle, refsVal, &success);
+ if (success) {
+ QmlV8ObjectData data = extractData(dataFromRef, refsVal);
+ objectData.type = data.type;
+ objectData.value = data.value;
+ objectData.properties = data.properties;
+ }
+ } else {
+ objectData.handle = dataMap.value(_(HANDLE)).toInt();
+ QString type = dataMap.value(_(TYPE)).toString();
+
+ if (type == _("undefined")) {
+ objectData.type = QByteArray("undefined");
+ objectData.value = QVariant(_("undefined"));
+
+ } else if (type == _("null")) {
+ objectData.type = QByteArray("null");
+ objectData.value= QVariant(_("null"));
+
+ } else if (type == _("boolean")) {
+ objectData.type = QByteArray("boolean");
+ objectData.value = dataMap.value(_(VALUE));
+
+ } else if (type == _("number")) {
+ objectData.type = QByteArray("number");
+ objectData.value = dataMap.value(_(VALUE));
+
+ } else if (type == _("string")) {
+ objectData.type = QByteArray("string");
+ objectData.value = dataMap.value(_(VALUE));
+
+ } else if (type == _("object")) {
+ objectData.type = QByteArray("object");
+ objectData.value = dataMap.value(_("className"));
+ objectData.properties = dataMap.value(_("properties")).toList();
+
+ } else if (type == _("function")) {
+ objectData.type = QByteArray("function");
+ objectData.value = dataMap.value(_(NAME));
+ objectData.properties = dataMap.value(_("properties")).toList();
+
+ } else if (type == _("script")) {
+ objectData.type = QByteArray("script");
+ objectData.value = dataMap.value(_(NAME));
+ }
+ }
+
+ return objectData;
+}
+
+void QmlEnginePrivate::clearCache()
+{
+ currentFrameScopes.clear();
+ updateLocalsAndWatchers.clear();
+}
+
+QByteArray QmlEnginePrivate::packMessage(const QByteArray &type, const QByteArray &message)
+{
+ SDEBUG(message);
+ QByteArray request;
+ QmlDebugStream rs(&request, QIODevice::WriteOnly);
+ QByteArray cmd = V8DEBUG;
+ rs << cmd << type << message;
+ return request;
+}
+
+QJsonObject QmlEnginePrivate::initObject()
+{
+ return QJsonObject {
+ {_(SEQ), ++sequence},
+ {_(TYPE), _(REQUEST)}
+ };
+}
+
+void QmlEnginePrivate::sendAndLogV8Request(const QJsonObject &request)
+{
+ const QByteArray msg = QJsonDocument(request).toJson(QJsonDocument::Compact);
+ engine->showMessage(QString::fromLatin1("%1 %2").arg(_(V8REQUEST), QString::fromUtf8(msg)), LogInput);
+ sendMessage(packMessage(V8REQUEST, msg));
+}
+
+void QmlEnginePrivate::expandObject(const QByteArray &iname, quint64 objectId)
+{
+ if (objectId == 0) {
+ //We may have got the global object
+ const WatchItem *watch = engine->watchHandler()->findItem(iname);
+ if (watch->value == QLatin1String("global")) {
+ StackHandler *stackHandler = engine->stackHandler();
+ if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
+ evaluate(watch->name, false, false, stackHandler->currentIndex());
+ evaluatingExpression.insert(sequence, QLatin1String(iname));
+ }
+ return;
+ }
+ }
+ localsAndWatchers.insertMulti(objectId, iname);
+ lookup(QList<int>() << objectId);
+}
+
+void QmlEnginePrivate::messageReceived(const QByteArray &data)
+{
+ QmlDebugStream ds(data);
+ QByteArray command;
+ ds >> command;
+
+ if (command == V8DEBUG) {
+ QByteArray type;
+ QByteArray response;
+ ds >> type >> response;
+
+ engine->showMessage(QLatin1String(type), LogOutput);
+ if (type == CONNECT) {
+ //debugging session started
+
+ } else if (type == INTERRUPT) {
+ //debug break requested
+
+ } else if (type == BREAKONSIGNAL) {
+ //break on signal handler requested
+
+ } else if (type == V8MESSAGE) {
+ const QString responseString = QLatin1String(response);
+ SDEBUG(responseString);
+ engine->showMessage(QLatin1String(V8MESSAGE) + QLatin1Char(' ') + responseString, LogOutput);
+
+ const QVariantMap resp =
+ QJsonDocument::fromJson(responseString.toUtf8()).toVariant().toMap();
+
+ const QString type(resp.value(_(TYPE)).toString());
+
+ if (type == _("response")) {
+
+ bool success = resp.value(_("success")).toBool();
+ if (!success) {
+ SDEBUG("Request was unsuccessful");
+ }
+
+ const QString debugCommand(resp.value(_(COMMAND)).toString());
+
+ if (debugCommand == _(DISCONNECT)) {
+ //debugging session ended
+
+ } else if (debugCommand == _(CONTINEDEBUGGING)) {
+ //do nothing, wait for next break
+
+ } else if (debugCommand == _(BACKTRACE)) {
+ if (success)
+ handleBacktrace(resp.value(_(BODY)), resp.value(_(REFS)));
+
+ } else if (debugCommand == _(LOOKUP)) {
+ if (success)
+ handleLookup(resp.value(_(BODY)), resp.value(_(REFS)));
+
+ } else if (debugCommand == _(EVALUATE)) {
+ int seq = resp.value(_("request_seq")).toInt();
+ if (success) {
+ handleEvaluate(seq, success, resp.value(_(BODY)), resp.value(_(REFS)));
+ } else {
+ QVariantMap map;
+ map.insert(_(TYPE), QVariant(_("string")));
+ map.insert(_(VALUE), resp.value(_("message")));
+ handleEvaluate(seq, success, QVariant(map), QVariant());
+ }
+
+ } else if (debugCommand == _(SETBREAKPOINT)) {
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "setbreakpoint",
+ // "body" : { "type" : <"function" or "script">
+ // "breakpoint" : <break point number of the new break point>
+ // }
+ // "running" : <is the VM running after sending this response>
+ // "success" : true
+ // }
+
+ int seq = resp.value(_("request_seq")).toInt();
+ const QVariantMap breakpointData = resp.value(_(BODY)).toMap();
+ int index = breakpointData.value(_("breakpoint")).toInt();
+
+ if (breakpointsSync.contains(seq)) {
+ BreakpointModelId id = breakpointsSync.take(seq);
+ breakpoints.insert(id, index);
+
+ //Is actual position info present? Then breakpoint was
+ //accepted
+ const QVariantList actualLocations =
+ breakpointData.value(_("actual_locations")).toList();
+ if (actualLocations.count()) {
+ //The breakpoint requested line should be same as
+ //actual line
+ BreakHandler *handler = engine->breakHandler();
+ Breakpoint bp = handler->breakpointById(id);
+ if (bp.state() != BreakpointInserted) {
+ BreakpointResponse br = bp.response();
+ br.lineNumber = breakpointData.value(_("line")).toInt() + 1;
+ bp.setResponse(br);
+ bp.notifyBreakpointInsertOk();
+ }
+ }
+
+
+ } else {
+ breakpointsTemp.append(index);
+ }
+
+
+ } else if (debugCommand == _(CLEARBREAKPOINT)) {
+ // DO NOTHING
+
+ } else if (debugCommand == _(SETEXCEPTIONBREAK)) {
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "setexceptionbreak",
+ // "body" : { "type" : <string: "all" or "uncaught" corresponding to the request.>,
+ // "enabled" : <bool: true if the break type is currently enabled as a result of the request>
+ // }
+ // "running" : true
+ // "success" : true
+ // }
+
+
+ } else if (debugCommand == _(FRAME)) {
+ if (success)
+ handleFrame(resp.value(_(BODY)), resp.value(_(REFS)));
+
+ } else if (debugCommand == _(SCOPE)) {
+ if (success)
+ handleScope(resp.value(_(BODY)), resp.value(_(REFS)));
+
+ } else if (debugCommand == _(SCRIPTS)) {
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "scripts",
+ // "body" : [ { "name" : <name of the script>,
+ // "id" : <id of the script>
+ // "lineOffset" : <line offset within the containing resource>
+ // "columnOffset" : <column offset within the containing resource>
+ // "lineCount" : <number of lines in the script>
+ // "data" : <optional data object added through the API>
+ // "source" : <source of the script if includeSource was specified in the request>
+ // "sourceStart" : <first 80 characters of the script if includeSource was not specified in the request>
+ // "sourceLength" : <total length of the script in characters>
+ // "scriptType" : <script type (see request for values)>
+ // "compilationType" : < How was this script compiled:
+ // 0 if script was compiled through the API
+ // 1 if script was compiled through eval
+ // >
+ // "evalFromScript" : <if "compilationType" is 1 this is the script from where eval was called>
+ // "evalFromLocation" : { line : < if "compilationType" is 1 this is the line in the script from where eval was called>
+ // column : < if "compilationType" is 1 this is the column in the script from where eval was called>
+ // ]
+ // "running" : <is the VM running after sending this response>
+ // "success" : true
+ // }
+
+ if (success) {
+ const QVariantList body = resp.value(_(BODY)).toList();
+
+ QStringList sourceFiles;
+ for (int i = 0; i < body.size(); ++i) {
+ const QVariantMap entryMap = body.at(i).toMap();
+ const int lineOffset = entryMap.value(QLatin1String("lineOffset")).toInt();
+ const int columnOffset = entryMap.value(QLatin1String("columnOffset")).toInt();
+ const QString name = entryMap.value(QLatin1String("name")).toString();
+ const QString source = entryMap.value(QLatin1String("source")).toString();
+
+ if (name.isEmpty())
+ continue;
+
+ if (!sourceFiles.contains(name))
+ sourceFiles << name;
+
+ updateScriptSource(name, lineOffset, columnOffset, source);
+ }
+
+ QMap<QString,QString> files;
+ foreach (const QString &file, sourceFiles) {
+ QString shortName = file;
+ QString fullName = engine->toFileInProject(file);
+ files.insert(shortName, fullName);
+ }
+
+ engine->sourceFilesHandler()->setSourceFiles(files);
+ //update open editors
+ }
+ } else if (debugCommand == _(VERSION)) {
+ engine->showMessage(QString(_("Using V8 Version: %1")).arg(
+ resp.value(_(BODY)).toMap().
+ value(_("V8Version")).toString()), LogOutput);
+
+ } else {
+ // DO NOTHING
+ }
+
+ } else if (type == _(EVENT)) {
+ const QString eventType(resp.value(_(EVENT)).toString());
+
+ if (eventType == _("break")) {
+ const QVariantMap breakData = resp.value(_(BODY)).toMap();
+ const QString invocationText = breakData.value(_("invocationText")).toString();
+ const QString scriptUrl = breakData.value(_("script")).toMap().value(_("name")).toString();
+ const QString sourceLineText = breakData.value(_("sourceLineText")).toString();
+
+ bool inferiorStop = true;
+
+ QList<int> v8BreakpointIds;
+ {
+ const QVariantList v8BreakpointIdList = breakData.value(_("breakpoints")).toList();
+ foreach (const QVariant &breakpointId, v8BreakpointIdList)
+ v8BreakpointIds << breakpointId.toInt();
+ }
+
+ if (!v8BreakpointIds.isEmpty() && invocationText.startsWith(_("[anonymous]()"))
+ && scriptUrl.endsWith(_(".qml"))
+ && sourceLineText.trimmed().startsWith(QLatin1Char('('))) {
+
+ // we hit most likely the anonymous wrapper function automatically generated for bindings
+ // -> relocate the breakpoint to column: 1 and continue
+
+ int newColumn = sourceLineText.indexOf(QLatin1Char('(')) + 1;
+ BreakHandler *handler = engine->breakHandler();
+
+ foreach (int v8Id, v8BreakpointIds) {
+ const BreakpointModelId id = breakpoints.key(v8Id);
+ Breakpoint bp = handler->breakpointById(id);
+ if (bp.isValid()) {
+ const BreakpointParameters &params = bp.parameters();
+
+ clearBreakpoint(v8Id);
+ setBreakpoint(QString(_(SCRIPTREGEXP)),
+ params.fileName,
+ params.enabled,
+ params.lineNumber,
+ newColumn,
+ QString(QString::fromLatin1(params.condition)),
+ params.ignoreCount);
+ breakpointsSync.insert(sequence, id);
+ }
+ }
+ continueDebugging(Continue);
+ inferiorStop = false;
+ }
+
+ //Skip debug break if this is an internal function
+ if (sourceLineText == _(INTERNAL_FUNCTION)) {
+ continueDebugging(previousStepAction);
+ inferiorStop = false;
+ }
+
+ if (inferiorStop) {
+ //Update breakpoint data
+ BreakHandler *handler = engine->breakHandler();
+ foreach (int v8Id, v8BreakpointIds) {
+ const BreakpointModelId id = breakpoints.key(v8Id);
+ Breakpoint bp = handler->breakpointById(id);
+ if (bp) {
+ BreakpointResponse br = bp.response();
+ if (br.functionName.isEmpty()) {
+ br.functionName = invocationText;
+ bp.setResponse(br);
+ }
+ if (bp.state() != BreakpointInserted) {
+ br.lineNumber = breakData.value(
+ _("sourceLine")).toInt() + 1;
+ bp.setResponse(br);
+ bp.notifyBreakpointInsertOk();
+ }
+ }
+ }
+
+ if (engine->state() == InferiorRunOk) {
+ foreach (const QVariant &breakpointId, v8BreakpointIds) {
+ if (breakpointsTemp.contains(breakpointId.toInt()))
+ clearBreakpoint(breakpointId.toInt());
+ }
+ engine->notifyInferiorSpontaneousStop();
+ backtrace();
+ } else if (engine->state() == InferiorStopOk) {
+ backtrace();
+ }
+ }
+
+ } else if (eventType == _("exception")) {
+ const QVariantMap body = resp.value(_(BODY)).toMap();
+ int lineNumber = body.value(_("sourceLine")).toInt() + 1;
+
+ const QVariantMap script = body.value(_("script")).toMap();
+ QUrl fileUrl(script.value(_(NAME)).toString());
+ QString filePath = engine->toFileInProject(fileUrl);
+
+ const QVariantMap exception = body.value(_("exception")).toMap();
+ QString errorMessage = exception.value(_("text")).toString();
+
+ QStringList messages = highlightExceptionCode(lineNumber, filePath, errorMessage);
+ foreach (const QString msg, messages)
+ engine->showMessage(msg, ConsoleOutput);
+
+ if (engine->state() == InferiorRunOk) {
+ engine->notifyInferiorSpontaneousStop();
+ backtrace();
+ }
+
+ if (engine->state() == InferiorStopOk)
+ backtrace();
+
+ } else if (eventType == _("afterCompile")) {
+ //Currently break point relocation is disabled.
+ //Uncomment the line below when it will be enabled.
+// listBreakpoints();
+ }
+
+ //Sometimes we do not get event type!
+ //This is most probably due to a wrong eval expression.
+ //Redirect output to console.
+ if (eventType.isEmpty()) {
+ bool success = resp.value(_("success")).toBool();
+ QVariantMap map;
+ map.insert(_(TYPE), QVariant(_("string")));
+ map.insert(_(VALUE), resp.value(_("message")));
+ //Since there is no sequence value, best estimate is
+ //last sequence value
+ handleEvaluate(sequence, success, QVariant(map), QVariant());
+ }
+
+ } //EVENT
+ } //V8MESSAGE
+
+ } else {
+ //DO NOTHING
+ }
+}
+
+void QmlEnginePrivate::handleBacktrace(const QVariant &bodyVal, const QVariant &refsVal)
+{
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "backtrace",
+ // "body" : { "fromFrame" : <number>
+ // "toFrame" : <number>
+ // "totalFrames" : <number>
+ // "frames" : <array of frames - see frame request for details>
+ // }
+ // "running" : <is the VM running after sending this response>
+ // "success" : true
+ // }
+
+ const QVariantMap body = bodyVal.toMap();
+ const QVariantList frames = body.value(_("frames")).toList();
+
+ int fromFrameIndex = body.value(_("fromFrame")).toInt();
+
+ QTC_ASSERT(0 == fromFrameIndex, return);
+
+ StackHandler *stackHandler = engine->stackHandler();
+ StackFrames stackFrames;
+ int i = 0;
+ stackIndexLookup.clear();
+ foreach (const QVariant &frame, frames) {
+ StackFrame stackFrame = extractStackFrame(frame, refsVal);
+ if (stackFrame.level < 0)
+ continue;
+ stackIndexLookup.insert(i, stackFrame.level);
+ stackFrame.level = i;
+ stackFrames << stackFrame;
+ i++;
+ }
+ stackHandler->setFrames(stackFrames);
+
+ //Populate locals and watchers wrt top frame
+ //Update all Locals visible in current scope
+ //Traverse the scope chain and store the local properties
+ //in a list and show them in the Locals Window.
+ handleFrame(frames.value(0), refsVal);
+}
+
+StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal, const QVariant &refsVal)
+{
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "frame",
+ // "body" : { "index" : <frame number>,
+ // "receiver" : <frame receiver>,
+ // "func" : <function invoked>,
+ // "script" : <script for the function>,
+ // "constructCall" : <boolean indicating whether the function was called as constructor>,
+ // "debuggerFrame" : <boolean indicating whether this is an internal debugger frame>,
+ // "arguments" : [ { name: <name of the argument - missing of anonymous argument>,
+ // value: <value of the argument>
+ // },
+ // ... <the array contains all the arguments>
+ // ],
+ // "locals" : [ { name: <name of the local variable>,
+ // value: <value of the local variable>
+ // },
+ // ... <the array contains all the locals>
+ // ],
+ // "position" : <source position>,
+ // "line" : <source line>,
+ // "column" : <source column within the line>,
+ // "sourceLineText" : <text for current source line>,
+ // "scopes" : [ <array of scopes, see scope request below for format> ],
+
+ // }
+ // "running" : <is the VM running after sending this response>
+ // "success" : true
+ // }
+
+ const QVariantMap body = bodyVal.toMap();
+
+ StackFrame stackFrame;
+ stackFrame.level = body.value(_("index")).toInt();
+ //Do not insert the frame corresponding to the internal function
+ if (body.value(QLatin1String("sourceLineText")) == QLatin1String(INTERNAL_FUNCTION)) {
+ stackFrame.level = -1;
+ return stackFrame;
+ }
+
+ QmlV8ObjectData objectData = extractData(body.value(_("func")), refsVal);
+ QString functionName = objectData.value.toString();
+ if (functionName.isEmpty())
+ functionName = tr("Anonymous Function");
+ stackFrame.function = functionName;
+
+ objectData = extractData(body.value(_("script")), refsVal);
+ stackFrame.file = engine->toFileInProject(objectData.value.toString());
+ stackFrame.usable = QFileInfo(stackFrame.file).isReadable();
+
+ objectData = extractData(body.value(_("receiver")), refsVal);
+ stackFrame.to = objectData.value.toString();
+
+ stackFrame.line = body.value(_("line")).toInt() + 1;
+
+ return stackFrame;
+}
+
+void QmlEnginePrivate::handleFrame(const QVariant &bodyVal, const QVariant &refsVal)
+{
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "frame",
+ // "body" : { "index" : <frame number>,
+ // "receiver" : <frame receiver>,
+ // "func" : <function invoked>,
+ // "script" : <script for the function>,
+ // "constructCall" : <boolean indicating whether the function was called as constructor>,
+ // "debuggerFrame" : <boolean indicating whether this is an internal debugger frame>,
+ // "arguments" : [ { name: <name of the argument - missing of anonymous argument>,
+ // value: <value of the argument>
+ // },
+ // ... <the array contains all the arguments>
+ // ],
+ // "locals" : [ { name: <name of the local variable>,
+ // value: <value of the local variable>
+ // },
+ // ... <the array contains all the locals>
+ // ],
+ // "position" : <source position>,
+ // "line" : <source line>,
+ // "column" : <source column within the line>,
+ // "sourceLineText" : <text for current source line>,
+ // "scopes" : [ <array of scopes, see scope request below for format> ],
+
+ // }
+ // "running" : <is the VM running after sending this response>
+ // "success" : true
+ // }
+ QVariantMap currentFrame = bodyVal.toMap();
+
+ StackHandler *stackHandler = engine->stackHandler();
+ WatchHandler * watchHandler = engine->watchHandler();
+ watchHandler->notifyUpdateStarted();
+ clearCache();
+
+ const int frameIndex = stackHandler->currentIndex();
+ QSet<QByteArray> expandedInames = watchHandler->expandedINames();
+ QHash<quint64, QByteArray> handlesToLookup;
+ // Store handles of all expanded watch data
+ foreach (const QByteArray &iname, expandedInames) {
+ const WatchItem *item = watchHandler->findItem(iname);
+ if (item && item->isLocal())
+ handlesToLookup.insert(item->id, iname);
+ }
+ if (frameIndex < 0)
+ return;
+ const StackFrame frame = stackHandler->currentFrame();
+ if (!frame.isUsable())
+ return;
+
+ //Set "this" variable
+ {
+ auto item = new WatchItem("local.this", QLatin1String("this"));
+ QmlV8ObjectData objectData = extractData(currentFrame.value(_("receiver")), refsVal);
+ item->id = objectData.handle;
+ item->type = objectData.type;
+ item->value = objectData.value.toString();
+ item->setHasChildren(objectData.properties.count());
+ // In case of global object, we do not get children
+ // Set children nevertheless and query later.
+ if (item->value == QLatin1String("global")) {
+ item->setHasChildren(true);
+ item->id = 0;
+ }
+ watchHandler->insertItem(item);
+ }
+
+ const QVariantList scopes = currentFrame.value(_("scopes")).toList();
+ foreach (const QVariant &scope, scopes) {
+ //Do not query for global types (0)
+ //Showing global properties increases clutter.
+ if (scope.toMap().value(_("type")).toInt() == 0)
+ continue;
+ int scopeIndex = scope.toMap().value(_("index")).toInt();
+ currentFrameScopes.append(scopeIndex);
+ this->scope(scopeIndex);
+ }
+ engine->gotoLocation(stackHandler->currentFrame());
+
+ // Expand watch data that were previously expanded
+ QHash<quint64, QByteArray>::const_iterator itEnd = handlesToLookup.constEnd();
+ for (QHash<quint64, QByteArray>::const_iterator it = handlesToLookup.constBegin(); it != itEnd; ++it)
+ expandObject(it.value(), it.key());
+ engine->stackFrameCompleted();
+}
+
+void QmlEnginePrivate::handleScope(const QVariant &bodyVal, const QVariant &refsVal)
+{
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "scope",
+ // "body" : { "index" : <index of this scope in the scope chain. Index 0 is the top scope
+ // and the global scope will always have the highest index for a
+ // frame>,
+ // "frameIndex" : <index of the frame>,
+ // "type" : <type of the scope:
+ // 0: Global
+ // 1: Local
+ // 2: With
+ // 3: Closure
+ // 4: Catch >,
+ // "object" : <the scope object defining the content of the scope.
+ // For local and closure scopes this is transient objects,
+ // which has a negative handle value>
+ // }
+ // "running" : <is the VM running after sending this response>
+ // "success" : true
+ // }
+ QVariantMap bodyMap = bodyVal.toMap();
+
+ //Check if the frameIndex is same as current Stack Index
+ StackHandler *stackHandler = engine->stackHandler();
+ if (bodyMap.value(_("frameIndex")).toInt() != stackHandler->currentIndex())
return;
- baseTextDocument->document()->setPlainText(textDocument->toPlainText());
+ QmlV8ObjectData objectData = extractData(bodyMap.value(_("object")), refsVal);
+
+ QList<int> handlesToLookup;
+ foreach (const QVariant &property, objectData.properties) {
+ QmlV8ObjectData localData = extractData(property, refsVal);
+ auto item = new WatchItem;
+ item->exp = localData.name;
+ //Check for v8 specific local data
+ if (item->exp.startsWith('.') || item->exp.isEmpty())
+ continue;
+
+ item->name = QLatin1String(item->exp);
+ item->iname = QByteArray("local.") + item->exp;
+
+ int handle = localData.handle;
+ if (localData.value.isValid()) {
+ item->id = handle;
+ item->type = localData.type;
+ item->value = localData.value.toString();
+ item->setHasChildren(localData.properties.count());
+ engine->watchHandler()->insertItem(item);
+ } else {
+ handlesToLookup << handle;
+ localsAndWatchers.insertMulti(handle, item->exp);
+ }
+ }
+
+ if (!handlesToLookup.isEmpty())
+ lookup(handlesToLookup);
+ else
+ engine->watchHandler()->notifyUpdateFinished();
}
-bool QmlEngine::canEvaluateScript(const QString &script)
+ConsoleItem *constructLogItemTree(ConsoleItem *parent,
+ const QmlV8ObjectData &objectData,
+ const QVariant &refsVal)
{
- m_interpreter.clearText();
- m_interpreter.appendText(script);
- return m_interpreter.canEvaluate();
+ bool sorted = boolSetting(SortStructMembers);
+ if (!objectData.value.isValid())
+ return 0;
+
+ QString text;
+ if (objectData.name.isEmpty())
+ text = objectData.value.toString();
+ else
+ text = QString(_("%1: %2")).arg(QString::fromLatin1(objectData.name))
+ .arg(objectData.value.toString());
+
+ ConsoleItem *item = new ConsoleItem(parent, ConsoleItem::UndefinedType, text);
+
+ QSet<QString> childrenFetched;
+ foreach (const QVariant &property, objectData.properties) {
+ const QmlV8ObjectData childObjectData = extractData(property, refsVal);
+ if (childObjectData.handle == objectData.handle)
+ continue;
+ ConsoleItem *child = constructLogItemTree(item, childObjectData, refsVal);
+ if (child) {
+ const QString text = child->text();
+ if (childrenFetched.contains(text))
+ continue;
+ childrenFetched.insert(text);
+ item->insertChild(child, sorted);
+ }
+ }
+
+ return item;
}
-bool QmlEngine::adjustBreakpointLineAndColumn(
- const QString &filePath, quint32 *line, quint32 *column, bool *valid)
+static void insertSubItems(WatchItem *parent, const QVariantList &properties, const QVariant &refsVal)
{
- bool success = false;
- //check if file is in the latest snapshot
- //ignoring documentChangedOnDisk
- //TODO:: update breakpoints if document is changed.
- ModelManagerInterface *mmIface = ModelManagerInterface::instance();
- if (mmIface) {
- Document::Ptr doc = mmIface->newestSnapshot().
- document(filePath);
- if (doc.isNull()) {
- ModelManagerInterface::instance()->updateSourceFiles(
- QStringList() << filePath, false);
+ QTC_ASSERT(parent, return);
+ foreach (const QVariant &property, properties) {
+ QmlV8ObjectData propertyData = extractData(property, refsVal);
+ auto item = new WatchItem;
+ item->name = QString::fromUtf8(propertyData.name);
+
+ // Check for v8 specific local data
+ if (item->name.startsWith(QLatin1Char('.')) || item->name.isEmpty())
+ continue;
+ if (parent->type == "object") {
+ if (parent->value == _("Array"))
+ item->exp = parent->exp + '[' + item->name.toLatin1() + ']';
+ else if (parent->value == _("Object"))
+ item->exp = parent->exp + '.' + item->name.toLatin1();
} else {
- ASTWalker walker;
- walker(doc->ast(), line, column);
- *valid = walker.done;
- success = true;
+ item->exp = item->name.toLatin1();
}
+
+ item->iname = parent->iname + '.' + item->name.toLatin1();
+ item->id = propertyData.handle;
+ item->type = propertyData.type;
+ item->value = propertyData.value.toString();
+ item->setHasChildren(propertyData.properties.count());
+ parent->appendChild(item);
}
- return success;
+}
+
+void QmlEnginePrivate::handleEvaluate(int sequence, bool success,
+ const QVariant &bodyVal, const QVariant &refsVal)
+{
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "evaluate",
+ // "body" : ...
+ // "running" : <is the VM running after sending this response>
+ // "success" : true
+ // }
+ WatchHandler *watchHandler = engine->watchHandler();
+ if (updateLocalsAndWatchers.contains(sequence)) {
+ updateLocalsAndWatchers.removeOne(sequence);
+ //Update the locals
+ foreach (int index, currentFrameScopes)
+ scope(index);
+ //Also update "this"
+ QByteArray iname("local.this");
+ const WatchItem *parent = watchHandler->findItem(iname);
+ localsAndWatchers.insertMulti(parent->id, iname);
+ lookup(QList<int>() << parent->id);
+
+ } else if (debuggerCommands.contains(sequence)) {
+ updateLocalsAndWatchers.removeOne(sequence);
+ QmlV8ObjectData body = extractData(bodyVal, refsVal);
+ if (auto consoleManager = ConsoleManagerInterface::instance()) {
+ if (ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), body, refsVal))
+ consoleManager->printToConsolePane(item);
+ }
+ //Update the locals
+ foreach (int index, currentFrameScopes)
+ scope(index);
+
+ } else {
+ QmlV8ObjectData body = extractData(bodyVal, refsVal);
+ if (evaluatingExpression.contains(sequence)) {
+ QString exp = evaluatingExpression.take(sequence);
+ //Do we have request to evaluate a local?
+ if (exp.startsWith(QLatin1String("local."))) {
+ WatchItem *item = watchHandler->findItem(exp.toLatin1());
+ insertSubItems(item, body.properties, refsVal);
+ } else {
+ QByteArray iname = watchHandler->watcherName(exp.toLatin1());
+ SDEBUG(QString(iname));
+
+ auto item = new WatchItem(iname, exp);
+ item->exp = exp.toLatin1();
+ item->id = body.handle;
+ if (success) {
+ item->type = body.type;
+ item->value = body.value.toString();
+ item->wantsChildren = body.properties.count();
+ } else {
+ //Do not set type since it is unknown
+ item->setError(body.value.toString());
+ }
+ watchHandler->insertItem(item);
+ insertSubItems(item, body.properties, refsVal);
+ }
+ //Insert the newly evaluated expression to the Watchers Window
+ }
+ }
+}
+
+void QmlEnginePrivate::handleLookup(const QVariant &bodyVal, const QVariant &refsVal)
+{
+ // { "seq" : <number>,
+ // "type" : "response",
+ // "request_seq" : <number>,
+ // "command" : "lookup",
+ // "body" : <array of serialized objects indexed using their handle>
+ // "running" : <is the VM running after sending this response>
+ // "success" : true
+ // }
+ const QVariantMap body = bodyVal.toMap();
+
+ QStringList handlesList = body.keys();
+ WatchHandler *watchHandler = engine->watchHandler();
+ foreach (const QString &handle, handlesList) {
+ QmlV8ObjectData bodyObjectData = extractData(body.value(handle), refsVal);
+ QByteArray prepend = localsAndWatchers.take(handle.toInt());
+
+ if (prepend.startsWith("local.") || prepend.startsWith("watch.")) {
+ // Data for expanded local/watch.
+ // Could be an object or function.
+ WatchItem *parent = watchHandler->findItem(prepend);
+ insertSubItems(parent, bodyObjectData.properties, refsVal);
+ } else {
+ //rest
+ auto item = new WatchItem;
+ item->exp = prepend;
+ item->name = QLatin1String(item->exp);
+ item->iname = QByteArray("local.") + item->exp;
+ item->id = handle.toInt();
+
+ item->type = bodyObjectData.type;
+ item->value = bodyObjectData.value.toString();
+
+ item->setHasChildren(bodyObjectData.properties.count());
+
+ engine->watchHandler()->insertItem(item);
+ }
+ }
+ engine->watchHandler()->notifyUpdateFinished();
+}
+
+void QmlEnginePrivate::stateChanged(State state)
+{
+ engine->clientStateChanged(state);
+
+ if (state == QmlDebugClient::Enabled) {
+ /// Start session.
+ flushSendBuffer();
+ connect();
+ //Query for the V8 version. This is
+ //only for logging to the debuggerlog
+ version();
+ }
+}
+
+void QmlEnginePrivate::sendMessage(const QByteArray &msg)
+{
+ if (state() == Enabled)
+ QmlDebugClient::sendMessage(msg);
+ else
+ sendBuffer.append(msg);
+}
+
+void QmlEnginePrivate::flushSendBuffer()
+{
+ QTC_ASSERT(state() == Enabled, return);
+ foreach (const QByteArray &msg, sendBuffer)
+ QmlDebugClient::sendMessage(msg);
+ sendBuffer.clear();
}
DebuggerEngine *createQmlEngine(const DebuggerRunParameters &sp)
@@ -1361,6 +2670,5 @@ DebuggerEngine *createQmlEngine(const DebuggerRunParameters &sp)
return new QmlEngine(sp);
}
-} // namespace Internal
-} // namespace Debugger
-
+} // Internal
+} // Debugger
diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h
index 35517e9c4b..2fe073aa49 100644
--- a/src/plugins/debugger/qml/qmlengine.h
+++ b/src/plugins/debugger/qml/qmlengine.h
@@ -31,28 +31,21 @@
#ifndef QMLENGINE_H
#define QMLENGINE_H
-#include "interactiveinterpreter.h"
-#include "qmladapter.h"
-#include "qmlinspectoradapter.h"
#include <debugger/debuggerengine.h>
-#include <projectexplorer/applicationlauncher.h>
#include <qmldebug/qdebugmessageclient.h>
+#include <qmldebug/qmldebugclient.h>
#include <qmldebug/qmloutputparser.h>
#include <qmljs/iscriptevaluator.h>
#include <qmljs/qmljsdocument.h>
-QT_FORWARD_DECLARE_CLASS(QTextDocument)
-
-namespace Core { class IDocument; }
-
-namespace TextEditor { class BaseTextEditor; }
-
namespace Debugger {
namespace Internal {
+class WatchData;
+class WatchItem;
+class QmlEnginePrivate;
class QmlAdapter;
-class WatchTreeView;
class QmlEngine : public DebuggerEngine, QmlJS::IScriptEvaluator
{
@@ -63,31 +56,11 @@ public:
DebuggerEngine *masterEngine = 0);
~QmlEngine();
- void notifyEngineRemoteServerRunning(const QByteArray &, int pid);
- void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result);
-
- bool canDisplayTooltip() const;
-
- void showMessage(const QString &msg, int channel = LogDebug,
- int timeout = -1) const;
- void gotoLocation(const Internal::Location &location);
-
- void filterApplicationMessage(const QString &msg, int channel);
- void inferiorSpontaneousStop();
-
- enum LogDirection {
- LogSend,
- LogReceive
- };
-
- void logMessage(const QString &service, LogDirection direction,
- const QString &str);
+ void filterApplicationMessage(const QString &msg, int channel) const;
- void setSourceFiles(const QStringList &fileNames);
- void updateScriptSource(const QString &fileName, int lineOffset,
- int columnOffset, const QString &source);
-
- void insertBreakpoint(Breakpoint bp);
+ void logServiceStateChange(const QString &service, float version,
+ QmlDebug::QmlDebugClient::State newState);
+ void logServiceActivity(const QString &service, const QString &logMessage);
private slots:
void disconnected();
@@ -96,23 +69,28 @@ private slots:
void errorMessageBoxFinished(int result);
void updateCurrentContext();
- void appendDebugOutput(QtMsgType type, const QString &message,
- const QmlDebug::QDebugContextInfo &info);
void tryToConnect(quint16 port = 0);
void beginConnection(quint16 port = 0);
void connectionEstablished();
void connectionStartupFailed();
void appStartupFailed(const QString &errorMessage);
- void connectionError(QDebugSupport::Error error);
- void serviceConnectionError(const QString &service);
void appendMessage(const QString &msg, Utils::OutputFormat);
void synchronizeWatchers();
private:
- // DebuggerEngine implementation.
+ void notifyEngineRemoteServerRunning(const QByteArray &, int pid);
+ void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result);
+
+ void showMessage(const QString &msg, int channel = LogDebug,
+ int timeout = -1) const;
+ void gotoLocation(const Internal::Location &location);
+ void insertBreakpoint(Breakpoint bp);
+
bool isSynchronous() const { return false; }
+ bool canDisplayTooltip() const { return false; }
+
void executeStep();
void executeStepOut();
void executeNext();
@@ -153,7 +131,6 @@ private:
void reloadSourceFiles();
void reloadFullStack() {}
- bool supportsThreads() const { return false; }
void updateWatchData(const QByteArray &iname);
void selectWatchData(const QByteArray &iname);
void executeDebuggerCommand(const QString &command, DebuggerLanguages languages);
@@ -162,36 +139,21 @@ private:
bool hasCapability(unsigned) const;
void quitDebugger();
-private:
void closeConnection();
void startApplicationLauncher();
void stopApplicationLauncher();
- bool isShadowBuildProject() const;
- QString fromShadowBuildFilename(const QString &filename) const;
- QString mangleFilenamePaths(const QString &filename,
- const QString &oldBasePath, const QString &newBasePath) const;
- QString qmlImportPath() const;
-
- void updateDocument(Core::IDocument *document, const QTextDocument *textDocument);
- bool canEvaluateScript(const QString &script);
- bool adjustBreakpointLineAndColumn(const QString &filePath, quint32 *line,
- quint32 *column, bool *valid);
-
- QmlAdapter m_adapter;
- QmlInspectorAdapter m_inspectorAdapter;
- ProjectExplorer::ApplicationLauncher m_applicationLauncher;
- QTimer m_noDebugOutputTimer;
- QmlDebug::QmlOutputParser m_outputParser;
- QHash<QString, QTextDocument*> m_sourceDocuments;
- QHash<QString, QWeakPointer<TextEditor::BaseTextEditor> > m_sourceEditors;
- InteractiveInterpreter m_interpreter;
- QHash<QString,Breakpoint> pendingBreakpoints;
- QList<quint32> queryIds;
- bool m_retryOnConnectFail;
- bool m_automaticConnect;
+ void connectionErrorOccurred(QDebugSupport::Error socketError);
+ void clientStateChanged(QmlDebug::QmlDebugClient::State state);
+ void checkConnectionState();
+ void showConnectionStateMessage(const QString &message);
+ void showConnectionErrorMessage(const QString &message);
+ bool isConnected() const;
+private:
friend class QmlCppEngine;
+ friend class QmlEnginePrivate;
+ QmlEnginePrivate *d;
};
} // namespace Internal
diff --git a/src/plugins/debugger/qml/qmlengineutils.cpp b/src/plugins/debugger/qml/qmlengineutils.cpp
new file mode 100644
index 0000000000..08670f46e9
--- /dev/null
+++ b/src/plugins/debugger/qml/qmlengineutils.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "qmlengine.h"
+
+#include <qmljs/parser/qmljsast_p.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
+#include <qmljs/consolemanagerinterface.h>
+
+#include <coreplugin/editormanager/documentmodel.h>
+
+#include <texteditor/textdocument.h>
+#include <texteditor/texteditor.h>
+
+#include <QTextBlock>
+
+using namespace Core;
+using namespace QmlDebug;
+using namespace QmlJS;
+using namespace QmlJS::AST;
+using namespace TextEditor;
+
+namespace Debugger {
+namespace Internal {
+
+class ASTWalker : public Visitor
+{
+public:
+ void operator()(Node *ast, quint32 *l, quint32 *c)
+ {
+ done = false;
+ line = l;
+ column = c;
+ Node::accept(ast, this);
+ }
+
+ bool preVisit(Node *ast)
+ {
+ return !done && ast->lastSourceLocation().startLine >= *line;
+ }
+
+ //Case 1: Breakpoint is between sourceStart(exclusive) and
+ // sourceEnd(inclusive) --> End tree walk.
+ //Case 2: Breakpoint is on sourceStart --> Check for the start
+ // of the first executable code. Set the line number and
+ // column number. End tree walk.
+ //Case 3: Breakpoint is on "unbreakable" code --> Find the next "breakable"
+ // code and check for Case 2. End tree walk.
+
+ //Add more types when suitable.
+
+ bool visit(UiScriptBinding *ast)
+ {
+ if (!ast->statement)
+ return true;
+
+ quint32 sourceStartLine = ast->firstSourceLocation().startLine;
+ quint32 statementStartLine;
+ quint32 statementColumn;
+
+ if (ast->statement->kind == Node::Kind_ExpressionStatement) {
+ statementStartLine = ast->statement->firstSourceLocation().startLine;
+ statementColumn = ast->statement->firstSourceLocation().startColumn;
+
+ } else if (ast->statement->kind == Node::Kind_Block) {
+ Block *block = static_cast<Block *>(ast->statement);
+ if (!block || !block->statements)
+ return true;
+ statementStartLine = block->statements->firstSourceLocation().startLine;
+ statementColumn = block->statements->firstSourceLocation().startColumn;
+
+ } else {
+ return true;
+ }
+
+
+ //Case 1
+ //Check for possible relocation within the binding statement
+
+ //Rewritten to (function <token>() { { }})
+ //The offset 16 is position of inner lbrace without token length.
+ const int offset = 16;
+
+ //Case 2
+ if (statementStartLine == *line) {
+ if (sourceStartLine == *line)
+ *column = offset + ast->qualifiedId->identifierToken.length;
+ done = true;
+ }
+
+ //Case 3
+ if (statementStartLine > *line) {
+ *line = statementStartLine;
+ if (sourceStartLine == *line)
+ *column = offset + ast->qualifiedId->identifierToken.length;
+ else
+ *column = statementColumn;
+ done = true;
+ }
+ return true;
+ }
+
+ bool visit(FunctionDeclaration *ast) {
+ quint32 sourceStartLine = ast->firstSourceLocation().startLine;
+ quint32 sourceStartColumn = ast->firstSourceLocation().startColumn;
+ quint32 statementStartLine = ast->body->firstSourceLocation().startLine;
+ quint32 statementColumn = ast->body->firstSourceLocation().startColumn;
+
+ //Case 1
+ //Check for possible relocation within the function declaration
+
+ //Case 2
+ if (statementStartLine == *line) {
+ if (sourceStartLine == *line)
+ *column = statementColumn - sourceStartColumn + 1;
+ done = true;
+ }
+
+ //Case 3
+ if (statementStartLine > *line) {
+ *line = statementStartLine;
+ if (sourceStartLine == *line)
+ *column = statementColumn - sourceStartColumn + 1;
+ else
+ *column = statementColumn;
+ done = true;
+ }
+ return true;
+ }
+
+ bool visit(EmptyStatement *ast)
+ {
+ *line = ast->lastSourceLocation().startLine + 1;
+ return true;
+ }
+
+ bool visit(VariableStatement *ast) { test(ast); return true; }
+ bool visit(VariableDeclarationList *ast) { test(ast); return true; }
+ bool visit(VariableDeclaration *ast) { test(ast); return true; }
+ bool visit(ExpressionStatement *ast) { test(ast); return true; }
+ bool visit(IfStatement *ast) { test(ast); return true; }
+ bool visit(DoWhileStatement *ast) { test(ast); return true; }
+ bool visit(WhileStatement *ast) { test(ast); return true; }
+ bool visit(ForStatement *ast) { test(ast); return true; }
+ bool visit(LocalForStatement *ast) { test(ast); return true; }
+ bool visit(ForEachStatement *ast) { test(ast); return true; }
+ bool visit(LocalForEachStatement *ast) { test(ast); return true; }
+ bool visit(ContinueStatement *ast) { test(ast); return true; }
+ bool visit(BreakStatement *ast) { test(ast); return true; }
+ bool visit(ReturnStatement *ast) { test(ast); return true; }
+ bool visit(WithStatement *ast) { test(ast); return true; }
+ bool visit(SwitchStatement *ast) { test(ast); return true; }
+ bool visit(CaseBlock *ast) { test(ast); return true; }
+ bool visit(CaseClauses *ast) { test(ast); return true; }
+ bool visit(CaseClause *ast) { test(ast); return true; }
+ bool visit(DefaultClause *ast) { test(ast); return true; }
+ bool visit(LabelledStatement *ast) { test(ast); return true; }
+ bool visit(ThrowStatement *ast) { test(ast); return true; }
+ bool visit(TryStatement *ast) { test(ast); return true; }
+ bool visit(Catch *ast) { test(ast); return true; }
+ bool visit(Finally *ast) { test(ast); return true; }
+ bool visit(FunctionExpression *ast) { test(ast); return true; }
+ bool visit(DebuggerStatement *ast) { test(ast); return true; }
+
+ void test(Node *ast)
+ {
+ quint32 statementStartLine = ast->firstSourceLocation().startLine;
+ //Case 1/2
+ if (statementStartLine <= *line && *line <= ast->lastSourceLocation().startLine)
+ done = true;
+
+ //Case 3
+ if (statementStartLine > *line) {
+ *line = statementStartLine;
+ *column = ast->firstSourceLocation().startColumn;
+ done = true;
+ }
+ }
+
+ bool done;
+ quint32 *line;
+ quint32 *column;
+};
+
+bool adjustBreakpointLineAndColumn(const QString &filePath, quint32 *line, quint32 *column, bool *valid)
+{
+ bool success = false;
+ //check if file is in the latest snapshot
+ //ignoring documentChangedOnDisk
+ //TODO:: update breakpoints if document is changed.
+ ModelManagerInterface *mmIface = ModelManagerInterface::instance();
+ if (mmIface) {
+ Document::Ptr doc = mmIface->newestSnapshot().document(filePath);
+ if (doc.isNull()) {
+ ModelManagerInterface::instance()->updateSourceFiles(
+ QStringList() << filePath, false);
+ } else {
+ ASTWalker walker;
+ walker(doc->ast(), line, column);
+ *valid = walker.done;
+ success = true;
+ }
+ }
+ return success;
+}
+
+void appendDebugOutput(QtMsgType type, const QString &message, const QDebugContextInfo &info)
+{
+ ConsoleItem::ItemType itemType;
+ switch (type) {
+ case QtDebugMsg:
+ itemType = ConsoleItem::DebugType;
+ break;
+ case QtWarningMsg:
+ itemType = ConsoleItem::WarningType;
+ break;
+ case QtCriticalMsg:
+ case QtFatalMsg:
+ itemType = ConsoleItem::ErrorType;
+ break;
+ default:
+ //This case is not possible
+ return;
+ }
+
+ if (auto consoleManager = ConsoleManagerInterface::instance()) {
+ ConsoleItem *item = new ConsoleItem(consoleManager->rootItem(), itemType, message);
+ item->file = info.file;
+ item->line = info.line;
+ consoleManager->printToConsolePane(item);
+ }
+}
+
+void clearExceptionSelection()
+{
+ QList<QTextEdit::ExtraSelection> selections;
+
+ foreach (IEditor *editor, DocumentModel::editorsForOpenedDocuments()) {
+ if (auto ed = qobject_cast<TextEditorWidget *>(editor->widget()))
+ ed->setExtraSelections(TextEditorWidget::DebuggerExceptionSelection, selections);
+ }
+}
+
+QStringList highlightExceptionCode(int lineNumber, const QString &filePath, const QString &errorMessage)
+{
+ QStringList messages;
+ QList<IEditor *> editors = DocumentModel::editorsForFilePath(filePath);
+
+ // set up the format for the errors
+ QTextCharFormat errorFormat;
+ errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ errorFormat.setUnderlineColor(Qt::red);
+
+ foreach (IEditor *editor, editors) {
+ TextEditorWidget *ed = qobject_cast<TextEditorWidget *>(editor->widget());
+ if (!ed)
+ continue;
+
+ QList<QTextEdit::ExtraSelection> selections;
+ QTextEdit::ExtraSelection sel;
+ sel.format = errorFormat;
+ QTextCursor c(ed->document()->findBlockByNumber(lineNumber - 1));
+ const QString text = c.block().text();
+ for (int i = 0; i < text.size(); ++i) {
+ if (!text.at(i).isSpace()) {
+ c.setPosition(c.position() + i);
+ break;
+ }
+ }
+ c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ sel.cursor = c;
+
+ sel.format.setToolTip(errorMessage);
+
+ selections.append(sel);
+ ed->setExtraSelections(TextEditorWidget::DebuggerExceptionSelection, selections);
+
+ messages.append(QString::fromLatin1("%1: %2: %3").arg(filePath).arg(lineNumber).arg(errorMessage));
+ }
+ return messages;
+}
+
+} // Internal
+} // Debugger
diff --git a/tests/manual/qml/testfiles/images.qml b/src/plugins/debugger/qml/qmlengineutils.h
index b115ee6540..c3f8c62111 100644
--- a/tests/manual/qml/testfiles/images.qml
+++ b/src/plugins/debugger/qml/qmlengineutils.h
@@ -28,30 +28,22 @@
**
****************************************************************************/
-import QtQuick 1.1
+#ifndef QMLENGINEUTILS_H
+#define QMLENGINEUTILS_H
-Rectangle {
- width: 640
- height: 480
+#include <qmldebug/qdebugmessageclient.h>
+#include <qmldebug/qmloutputparser.h>
- Image {
- id: image1
- x: 20
- y: 18
- source: "images/qtcreator.png"
- }
+namespace Debugger {
+namespace Internal {
- Image {
- id: image2
- x: 327
- y: 18
- source: "images/qtcreator.jpg"
- }
+bool adjustBreakpointLineAndColumn(const QString &filePath, quint32 *line, quint32 *column, bool *valid);
+void appendDebugOutput(QtMsgType type, const QString &message, const QmlDebug::QDebugContextInfo &info);
- Image {
- id: image3
- x: 20
- y: 288
- source: "images/qtcreator.ico"
- }
-}
+void clearExceptionSelection();
+QStringList highlightExceptionCode(int lineNumber, const QString &filePath, const QString &errorMessage);
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // QMLENGINEUTILS_H
diff --git a/src/plugins/debugger/qml/qmlinspectoradapter.cpp b/src/plugins/debugger/qml/qmlinspectoradapter.cpp
index f98d73959e..43f305b5ff 100644
--- a/src/plugins/debugger/qml/qmlinspectoradapter.cpp
+++ b/src/plugins/debugger/qml/qmlinspectoradapter.cpp
@@ -30,8 +30,9 @@
#include "qmlinspectoradapter.h"
-#include "qmladapter.h"
+#include "qmlengine.h"
#include "qmlinspectoragent.h"
+
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerstringutils.h>
@@ -60,15 +61,12 @@ namespace Internal {
* QmlInspectorAdapter manages the clients for the inspector, and the
* integration with the text editor.
*/
-QmlInspectorAdapter::QmlInspectorAdapter(QmlAdapter *debugAdapter,
- DebuggerEngine *engine,
- QObject *parent)
- : QObject(parent)
- , m_debugAdapter(debugAdapter)
- , m_engine(engine)
+QmlInspectorAdapter::QmlInspectorAdapter(QmlEngine *engine, QmlDebugConnection *connection)
+ : m_qmlEngine(engine)
+ , m_masterEngine(engine)
, m_engineClient(0)
, m_toolsClient(0)
- , m_agent(new QmlInspectorAgent(engine, this))
+ , m_agent(new QmlInspectorAgent(engine))
, m_targetToSync(NoTarget)
, m_debugIdToSelect(-1)
, m_currentSelectedDebugId(-1)
@@ -79,16 +77,15 @@ QmlInspectorAdapter::QmlInspectorAdapter(QmlAdapter *debugAdapter,
, m_showAppOnTopAction(action(ShowAppOnTop))
, m_engineClientConnected(false)
{
- if (!m_engine->isMasterEngine())
- m_engine = m_engine->masterEngine();
- connect(m_engine, &DebuggerEngine::stateChanged,
+ if (!m_masterEngine->isMasterEngine())
+ m_masterEngine = m_masterEngine->masterEngine();
+ connect(m_masterEngine, &DebuggerEngine::stateChanged,
this, &QmlInspectorAdapter::onEngineStateChanged);
connect(m_agent, &QmlInspectorAgent::objectFetched,
this, &QmlInspectorAdapter::onObjectFetched);
connect(m_agent, &QmlInspectorAgent::jumpToObjectDefinition,
this, &QmlInspectorAdapter::jumpToObjectDefinitionInEditor);
- QmlDebugConnection *connection = m_debugAdapter->connection();
auto engineClient1 = new DeclarativeEngineDebugClient(connection);
connect(engineClient1, &BaseEngineDebugClient::newState,
this, &QmlInspectorAdapter::clientStateChanged);
@@ -186,7 +183,7 @@ void QmlInspectorAdapter::clientStateChanged(QmlDebugClient::State state)
version = client->remoteVersion();
}
- m_debugAdapter->logServiceStateChange(serviceName, version, state);
+ m_qmlEngine->logServiceStateChange(serviceName, version, state);
}
void QmlInspectorAdapter::toolsClientStateChanged(QmlDebugClient::State state)
@@ -199,7 +196,7 @@ void QmlInspectorAdapter::toolsClientStateChanged(QmlDebugClient::State state)
connect(client, &BaseToolsClient::currentObjectsChanged,
this, &QmlInspectorAdapter::selectObjectsFromToolsClient);
connect(client, &BaseToolsClient::logActivity,
- m_debugAdapter, &QmlAdapter::logServiceActivity);
+ m_qmlEngine, &QmlEngine::logServiceActivity);
connect(client, &BaseToolsClient::reloaded, this, &QmlInspectorAdapter::onReloaded);
// register actions here
@@ -217,15 +214,15 @@ void QmlInspectorAdapter::toolsClientStateChanged(QmlDebugClient::State state)
Core::ICore::addAdditionalContext(m_inspectorToolsContext);
m_toolsClientConnected = true;
- onEngineStateChanged(m_engine->state());
+ onEngineStateChanged(m_masterEngine->state());
if (m_showAppOnTopAction->isChecked())
m_toolsClient->showAppOnTop(true);
} else if (m_toolsClientConnected && client == m_toolsClient) {
- disconnect(client, SIGNAL(currentObjectsChanged(QList<int>)),
- this, SLOT(selectObjectsFromToolsClient(QList<int>)));
- disconnect(client, SIGNAL(logActivity(QString,QString)),
- m_debugAdapter, SLOT(logServiceActivity(QString,QString)));
+ disconnect(client, &BaseToolsClient::currentObjectsChanged,
+ this, &QmlInspectorAdapter::selectObjectsFromToolsClient);
+ disconnect(client, &BaseToolsClient::logActivity,
+ m_qmlEngine, &QmlEngine::logServiceActivity);
Core::ActionManager::unregisterAction(m_selectAction, Core::Id(Constants::QML_SELECTTOOL));
Core::ActionManager::unregisterAction(m_zoomAction, Core::Id(Constants::QML_ZOOMTOOL));
@@ -316,13 +313,13 @@ void QmlInspectorAdapter::setActiveEngineClient(BaseEngineDebugClient *client)
void QmlInspectorAdapter::showConnectionStateMessage(const QString &message)
{
- m_engine->showMessage(_("QML Inspector: ") + message, LogStatus);
+ m_masterEngine->showMessage(_("QML Inspector: ") + message, LogStatus);
}
void QmlInspectorAdapter::jumpToObjectDefinitionInEditor(
const FileReference &objSource, int debugId)
{
- const QString fileName = m_engine->toFileInProject(objSource.url());
+ const QString fileName = m_masterEngine->toFileInProject(objSource.url());
Core::EditorManager::openEditorAt(fileName, objSource.lineNumber());
if (debugId != -1 && debugId != m_currentSelectedDebugId) {
diff --git a/src/plugins/debugger/qml/qmlinspectoradapter.h b/src/plugins/debugger/qml/qmlinspectoradapter.h
index d448a3cc7a..961aa11957 100644
--- a/src/plugins/debugger/qml/qmlinspectoradapter.h
+++ b/src/plugins/debugger/qml/qmlinspectoradapter.h
@@ -41,13 +41,14 @@ class BaseEngineDebugClient;
class BaseToolsClient;
class ObjectReference;
class FileReference;
+class QmlDebugConnection;
}
namespace Debugger {
namespace Internal {
class DebuggerEngine;
-class QmlAdapter;
+class QmlEngine;
class QmlInspectorAgent;
class QmlInspectorAdapter : public QObject
@@ -55,8 +56,7 @@ class QmlInspectorAdapter : public QObject
Q_OBJECT
public:
- QmlInspectorAdapter(QmlAdapter *debugAdapter, DebuggerEngine *engine,
- QObject *parent = 0);
+ QmlInspectorAdapter(QmlEngine *engine, QmlDebug::QmlDebugConnection *connection);
~QmlInspectorAdapter();
QmlDebug::BaseEngineDebugClient *engineClient() const;
@@ -96,8 +96,8 @@ private:
void enableTools(const bool enable);
- QmlAdapter *m_debugAdapter;
- DebuggerEngine *m_engine; // Master Engine
+ QmlEngine *m_qmlEngine;
+ DebuggerEngine *m_masterEngine;
QmlDebug::BaseEngineDebugClient *m_engineClient;
QHash<QString, QmlDebug::BaseEngineDebugClient*> m_engineClients;
QmlDebug::BaseToolsClient *m_toolsClient;
diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp
index 2a4dc61478..64bd8cb089 100644
--- a/src/plugins/debugger/qml/qmlinspectoragent.cpp
+++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp
@@ -686,6 +686,7 @@ void QmlInspectorAgent::insertObjectInTree(const ObjectReference &object)
m_objectToSelect = -1;
}
m_debuggerEngine->watchHandler()->updateWatchersWindow();
+ m_debuggerEngine->watchHandler()->reexpandItems();
}
void QmlInspectorAgent::buildDebugIdHashRecursive(const ObjectReference &ref)
diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
deleted file mode 100644
index c821da13a0..0000000000
--- a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
+++ /dev/null
@@ -1,1799 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#include "qmlv8debuggerclient.h"
-#include "qmlv8debuggerclientconstants.h"
-#include "qmlengine.h"
-
-#include <debugger/debuggerstringutils.h>
-#include <debugger/watchhandler.h>
-#include <debugger/breakhandler.h>
-#include <debugger/stackhandler.h>
-#include <debugger/debuggercore.h>
-#include <debugger/debuggeractions.h>
-
-#include <utils/qtcassert.h>
-#include <texteditor/texteditor.h>
-
-#include <coreplugin/editormanager/documentmodel.h>
-
-#include <qmljs/consolemanagerinterface.h>
-
-#include <QTextBlock>
-#include <QFileInfo>
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QJsonObject>
-
-#define DEBUG_QML 0
-#if DEBUG_QML
-# define SDEBUG(s) qDebug() << s << '\n'
-#else
-# define SDEBUG(s)
-#endif
-
-using namespace Core;
-using QmlDebug::QmlDebugStream;
-
-namespace Debugger {
-namespace Internal {
-
-typedef QPair<QByteArray, QByteArray> WatchDataPair;
-
-struct QmlV8ObjectData {
- int handle;
- QByteArray name;
- QByteArray type;
- QVariant value;
- QVariantList properties;
-};
-
-class QmlV8DebuggerClientPrivate
-{
-public:
- explicit QmlV8DebuggerClientPrivate(QmlV8DebuggerClient *q) :
- q(q),
- sequence(-1),
- engine(0),
- previousStepAction(QmlV8DebuggerClient::Continue)
- {
- }
-
- void connect();
- void disconnect();
-
- void interrupt();
- void continueDebugging(QmlV8DebuggerClient::StepAction stepAction);
-
- void evaluate(const QString expr, bool global = false, bool disableBreak = false,
- int frame = -1, bool addContext = false);
- void lookup(const QList<int> handles, bool includeSource = false);
- void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
- void frame(int number = -1);
- void scope(int number = -1, int frameNumber = -1);
- void scripts(int types = 4, const QList<int> ids = QList<int>(),
- bool includeSource = false, const QVariant filter = QVariant());
-
- void setBreakpoint(const QString type, const QString target,
- bool enabled = true,int line = 0, int column = 0,
- const QString condition = QString(), int ignoreCount = -1);
- void clearBreakpoint(int breakpoint);
- void setExceptionBreak(QmlV8DebuggerClient::Exceptions type, bool enabled = false);
-
- void version();
- //void profile(ProfileCommand command); //NOT SUPPORTED
- void clearCache();
-
- void sendAndLogV8Request(const QJsonObject &request);
- void logSendMessage(const QString &msg) const;
- void logReceiveMessage(const QString &msg) const;
-
-private:
- QByteArray packMessage(const QByteArray &type, const QByteArray &message = QByteArray());
- QJsonObject initObject();
-
-public:
- QmlV8DebuggerClient *q;
-
- int sequence;
- QmlEngine *engine;
- QHash<BreakpointModelId, int> breakpoints;
- QHash<int, BreakpointModelId> breakpointsSync;
- QList<int> breakpointsTemp;
-
- QHash<int, QString> evaluatingExpression;
- QHash<int, QByteArray> localsAndWatchers;
- QList<int> updateLocalsAndWatchers;
- QList<int> debuggerCommands;
-
- //Cache
- QList<int> currentFrameScopes;
- QHash<int, int> stackIndexLookup;
-
- QmlV8DebuggerClient::StepAction previousStepAction;
-};
-
-///////////////////////////////////////////////////////////////////////
-//
-// QmlV8DebuggerClientPrivate
-//
-///////////////////////////////////////////////////////////////////////
-
-void QmlV8DebuggerClientPrivate::connect()
-{
- logSendMessage(QString(_("%1 %2")).arg(_(V8DEBUG), _(CONNECT)));
- q->sendMessage(packMessage(CONNECT));
-}
-
-void QmlV8DebuggerClientPrivate::disconnect()
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "disconnect",
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(DISCONNECT));
-
- const QJsonDocument jsonMessage(jsonVal);
- logSendMessage(QString::fromLatin1("%1 %2")
- .arg(_(V8DEBUG),
- QString::fromUtf8(jsonMessage.toJson(QJsonDocument::Compact))));
- q->sendMessage(packMessage(DISCONNECT, jsonMessage.toJson(QJsonDocument::Compact)));
-}
-
-void QmlV8DebuggerClientPrivate::interrupt()
-{
- logSendMessage(QString(_("%1 %2")).arg(_(V8DEBUG), _(INTERRUPT)));
- q->sendMessage(packMessage(INTERRUPT));
-}
-
-void QmlV8DebuggerClientPrivate::continueDebugging(QmlV8DebuggerClient::StepAction action)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "continue",
- // "arguments" : { "stepaction" : <"in", "next" or "out">,
- // "stepcount" : <number of steps (default 1)>
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(CONTINEDEBUGGING));
-
- if (action != QmlV8DebuggerClient::Continue) {
- QJsonObject args;
- switch (action) {
- case QmlV8DebuggerClient::In:
- args.insert(_(STEPACTION), _(IN));
- break;
- case QmlV8DebuggerClient::Out:
- args.insert(_(STEPACTION), _(OUT));
- break;
- case QmlV8DebuggerClient::Next:
- args.insert(_(STEPACTION), _(NEXT));
- break;
- default:break;
- }
-
- jsonVal.insert(_(ARGUMENTS), args);
- }
- sendAndLogV8Request(jsonVal);
- previousStepAction = action;
-}
-
-void QmlV8DebuggerClientPrivate::evaluate(const QString expr, bool global,
- bool disableBreak, int frame,
- bool addContext)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "evaluate",
- // "arguments" : { "expression" : <expression to evaluate>,
- // "frame" : <number>,
- // "global" : <boolean>,
- // "disable_break" : <boolean>,
- // "additional_context" : [
- // { "name" : <name1>, "handle" : <handle1> },
- // { "name" : <name2>, "handle" : <handle2> },
- // ...
- // ]
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(EVALUATE));
-
- QJsonObject args {
- { _(EXPRESSION), expr }
- };
-
- if (frame != -1)
- args.insert(_(FRAME), frame);
-
- if (global)
- args.insert(_(GLOBAL), global);
-
- if (disableBreak)
- args.insert(_(DISABLE_BREAK), disableBreak);
-
- if (addContext) {
- WatchHandler *watchHandler = engine->watchHandler();
- QAbstractItemModel *watchModel = watchHandler->model();
- int rowCount = watchModel->rowCount();
-
- QJsonArray ctxtList;
- while (rowCount) {
- QModelIndex index = watchModel->index(--rowCount, 0);
- const WatchData *data = watchHandler->watchItem(index);
- const QJsonObject ctxt {
- { _(NAME), data->name },
- { _(HANDLE), int(data->id) }
- };
-
- ctxtList.push_front(ctxt);
- }
-
- args.insert(_(ADDITIONAL_CONTEXT), ctxtList);
- }
-
- jsonVal.insert(_(ARGUMENTS), args);
-
- sendAndLogV8Request(jsonVal);
-}
-
-void QmlV8DebuggerClientPrivate::lookup(QList<int> handles, bool includeSource)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "lookup",
- // "arguments" : { "handles" : <array of handles>,
- // "includeSource" : <boolean indicating whether
- // the source will be included when
- // script objects are returned>,
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(LOOKUP));
-
- QJsonObject args;
-
- QJsonArray array;
- foreach (int handle, handles)
- array.push_back(handle);
- args.insert(_(HANDLES), array);
-
- if (includeSource)
- args.insert(_(INCLUDESOURCE), includeSource);
-
- jsonVal.insert(_(ARGUMENTS), args);
-
- sendAndLogV8Request(jsonVal);
-}
-
-void QmlV8DebuggerClientPrivate::backtrace(int fromFrame, int toFrame, bool bottom)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "backtrace",
- // "arguments" : { "fromFrame" : <number>
- // "toFrame" : <number>
- // "bottom" : <boolean, set to true if the bottom of the
- // stack is requested>
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(BACKTRACE));
-
- QJsonObject args;
-
- if (fromFrame != -1)
- args.insert(_(FROMFRAME), fromFrame);
-
- if (toFrame != -1)
- args.insert(_(TOFRAME), toFrame);
-
- if (bottom)
- args.insert(_(BOTTOM), bottom);
-
- jsonVal.insert(_(ARGUMENTS), args);
-
- sendAndLogV8Request(jsonVal);
-}
-
-void QmlV8DebuggerClientPrivate::frame(int number)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "frame",
- // "arguments" : { "number" : <frame number>
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(FRAME));
-
- if (number != -1) {
- const QJsonObject args {
- { _(NUMBER), number }
- };
-
- jsonVal.insert(_(ARGUMENTS), args);
- }
-
- sendAndLogV8Request(jsonVal);
-}
-
-void QmlV8DebuggerClientPrivate::scope(int number, int frameNumber)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "scope",
- // "arguments" : { "number" : <scope number>
- // "frameNumber" : <frame number, optional uses selected
- // frame if missing>
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(SCOPE));
-
- if (number != -1) {
- QJsonObject args {
- { _(NUMBER), number }
- };
-
- if (frameNumber != -1)
- args.insert(_(FRAMENUMBER), frameNumber);
-
- jsonVal.insert(_(ARGUMENTS), args);
- }
-
- sendAndLogV8Request(jsonVal);
-}
-
-void QmlV8DebuggerClientPrivate::scripts(int types, const QList<int> ids, bool includeSource,
- const QVariant filter)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "scripts",
- // "arguments" : { "types" : <types of scripts to retrieve
- // set bit 0 for native scripts
- // set bit 1 for extension scripts
- // set bit 2 for normal scripts
- // (default is 4 for normal scripts)>
- // "ids" : <array of id's of scripts to return. If this is not specified all scripts are requrned>
- // "includeSource" : <boolean indicating whether the source code should be included for the scripts returned>
- // "filter" : <string or number: filter string or script id.
- // If a number is specified, then only the script with the same number as its script id will be retrieved.
- // If a string is specified, then only scripts whose names contain the filter string will be retrieved.>
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(SCRIPTS));
-
- QJsonObject args {
- { _(TYPES), types }
- };
-
- if (ids.count()) {
- QJsonArray array;
- foreach (int id, ids) {
- array.push_back(id);
- }
- args.insert(_(IDS), array);
- }
-
- if (includeSource)
- args.insert(_(INCLUDESOURCE), includeSource);
-
- QJsonValue filterValue;
- if (filter.type() == QVariant::String)
- filterValue = filter.toString();
- else if (filter.type() == QVariant::Int)
- filterValue = filter.toInt();
- else
- QTC_CHECK(!filter.isValid());
-
- args.insert(_(FILTER), filterValue);
-
- jsonVal.insert(_(ARGUMENTS), args);
-
- sendAndLogV8Request(jsonVal);
-}
-
-void QmlV8DebuggerClientPrivate::setBreakpoint(const QString type, const QString target,
- bool enabled, int line, int column,
- const QString condition, int ignoreCount)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "setbreakpoint",
- // "arguments" : { "type" : <"function" or "script" or "scriptId" or "scriptRegExp">
- // "target" : <function expression or script identification>
- // "line" : <line in script or function>
- // "column" : <character position within the line>
- // "enabled" : <initial enabled state. True or false, default is true>
- // "condition" : <string with break point condition>
- // "ignoreCount" : <number specifying the number of break point hits to ignore, default value is 0>
- // }
- // }
- if (type == _(EVENT)) {
- QByteArray params;
- QmlDebugStream rs(&params, QIODevice::WriteOnly);
- rs << target.toUtf8() << enabled;
- logSendMessage(QString(_("%1 %2 %3 %4")).arg(_(V8DEBUG), _(BREAKONSIGNAL), target, enabled?_("enabled"):_("disabled")));
- q->sendMessage(packMessage(BREAKONSIGNAL, params));
-
- } else {
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(SETBREAKPOINT));
-
- QJsonObject args {
- { _(TYPE), type },
- { _(ENABLED), enabled }
- };
- if (type == _(SCRIPTREGEXP))
- args.insert(_(TARGET),
- Utils::FileName::fromString(target).fileName());
- else
- args.insert(_(TARGET), target);
-
- if (line)
- args.insert(_(LINE), line - 1);
-
- if (column)
- args.insert(_(COLUMN), column - 1);
-
- if (!condition.isEmpty())
- args.insert(_(CONDITION), condition);
-
- if (ignoreCount != -1)
- args.insert(_(IGNORECOUNT), ignoreCount);
-
- jsonVal.insert(_(ARGUMENTS), args);
-
- sendAndLogV8Request(jsonVal);
- }
-}
-
-void QmlV8DebuggerClientPrivate::clearBreakpoint(int breakpoint)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "clearbreakpoint",
- // "arguments" : { "breakpoint" : <number of the break point to clear>
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(CLEARBREAKPOINT));
-
- QJsonObject args {
- { _(BREAKPOINT), breakpoint }
- };
-
- jsonVal.insert(_(ARGUMENTS), args);
-
- sendAndLogV8Request(jsonVal);
-}
-
-void QmlV8DebuggerClientPrivate::setExceptionBreak(QmlV8DebuggerClient::Exceptions type,
- bool enabled)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "setexceptionbreak",
- // "arguments" : { "type" : <string: "all", or "uncaught">,
- // "enabled" : <optional bool: enables the break type if true>
- // }
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(SETEXCEPTIONBREAK));
-
- QJsonObject args;
-
- if (type == QmlV8DebuggerClient::AllExceptions)
- args.insert(_(TYPE), _(ALL));
- //Not Supported
- // else if (type == QmlV8DebuggerClient::UncaughtExceptions)
- // args.setProperty(_(TYPE),QScriptValue(_(UNCAUGHT)));
-
- if (enabled)
- args.insert(_(ENABLED), enabled);
-
- jsonVal.insert(_(ARGUMENTS), args);
-
- sendAndLogV8Request(jsonVal);
-}
-
-void QmlV8DebuggerClientPrivate::version()
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "version",
- // }
- QJsonObject jsonVal = initObject();
- jsonVal.insert(_(COMMAND), _(VERSION));
-
- sendAndLogV8Request(jsonVal);
-}
-
-//void QmlV8DebuggerClientPrivate::profile(ProfileCommand command)
-//{
-//// { "seq" : <number>,
-//// "type" : "request",
-//// "command" : "profile",
-//// "arguments" : { "command" : "resume" or "pause" }
-//// }
-// QScriptValue jsonVal = initObject();
-// jsonVal.setProperty(_(COMMAND), QScriptValue(_(PROFILE)));
-
-// QScriptValue args = m_parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT)));
-
-// if (command == Resume)
-// args.setProperty(_(COMMAND), QScriptValue(_(RESUME)));
-// else
-// args.setProperty(_(COMMAND), QScriptValue(_(PAUSE)));
-
-// args.setProperty(_("modules"), QScriptValue(1));
-// jsonVal.setProperty(_(ARGUMENTS), args);
-
-// const QScriptValue jsonMessage = m_stringifier.call(QScriptValue(), QScriptValueList() << jsonVal);
-// logSendMessage(QString(_("%1 %2 %3")).arg(_(V8DEBUG), _(V8REQUEST), jsonMessage.toString()));
-// q->sendMessage(packMessage(V8REQUEST, jsonMessage.toString().toUtf8()));
-//}
-
-QVariant valueFromRef(int handle, const QVariant &refsVal, bool *success)
-{
- *success = false;
- QVariant variant;
- const QVariantList refs = refsVal.toList();
- foreach (const QVariant &ref, refs) {
- const QVariantMap refData = ref.toMap();
- if (refData.value(_(HANDLE)).toInt() == handle) {
- variant = refData;
- *success = true;
- break;
- }
- }
- return variant;
-}
-
-QmlV8ObjectData extractData(const QVariant &data, const QVariant &refsVal)
-{
- // { "handle" : <handle>,
- // "type" : <"undefined", "null", "boolean", "number", "string", "object", "function" or "frame">
- // }
-
- // {"handle":<handle>,"type":"undefined"}
-
- // {"handle":<handle>,"type":"null"}
-
- // { "handle":<handle>,
- // "type" : <"boolean", "number" or "string">
- // "value" : <JSON encoded value>
- // }
-
- // {"handle":7,"type":"boolean","value":true}
-
- // {"handle":8,"type":"number","value":42}
-
- // { "handle" : <handle>,
- // "type" : "object",
- // "className" : <Class name, ECMA-262 property [[Class]]>,
- // "constructorFunction" : {"ref":<handle>},
- // "protoObject" : {"ref":<handle>},
- // "prototypeObject" : {"ref":<handle>},
- // "properties" : [ {"name" : <name>,
- // "ref" : <handle>
- // },
- // ...
- // ]
- // }
-
- // { "handle" : <handle>,
- // "type" : "function",
- // "className" : "Function",
- // "constructorFunction" : {"ref":<handle>},
- // "protoObject" : {"ref":<handle>},
- // "prototypeObject" : {"ref":<handle>},
- // "name" : <function name>,
- // "inferredName" : <inferred function name for anonymous functions>
- // "source" : <function source>,
- // "script" : <reference to function script>,
- // "scriptId" : <id of function script>,
- // "position" : <function begin position in script>,
- // "line" : <function begin source line in script>,
- // "column" : <function begin source column in script>,
- // "properties" : [ {"name" : <name>,
- // "ref" : <handle>
- // },
- // ...
- // ]
- // }
-
- QmlV8ObjectData objectData;
- const QVariantMap dataMap = data.toMap();
-
- objectData.name = dataMap.value(_(NAME)).toByteArray();
-
- if (dataMap.contains(_(REF))) {
- objectData.handle = dataMap.value(_(REF)).toInt();
- bool success;
- QVariant dataFromRef = valueFromRef(objectData.handle, refsVal, &success);
- if (success) {
- QmlV8ObjectData data = extractData(dataFromRef, refsVal);
- objectData.type = data.type;
- objectData.value = data.value;
- objectData.properties = data.properties;
- }
- } else {
- objectData.handle = dataMap.value(_(HANDLE)).toInt();
- QString type = dataMap.value(_(TYPE)).toString();
-
- if (type == _("undefined")) {
- objectData.type = QByteArray("undefined");
- objectData.value = QVariant(_("undefined"));
-
- } else if (type == _("null")) {
- objectData.type = QByteArray("null");
- objectData.value= QVariant(_("null"));
-
- } else if (type == _("boolean")) {
- objectData.type = QByteArray("boolean");
- objectData.value = dataMap.value(_(VALUE));
-
- } else if (type == _("number")) {
- objectData.type = QByteArray("number");
- objectData.value = dataMap.value(_(VALUE));
-
- } else if (type == _("string")) {
- objectData.type = QByteArray("string");
- objectData.value = dataMap.value(_(VALUE));
-
- } else if (type == _("object")) {
- objectData.type = QByteArray("object");
- objectData.value = dataMap.value(_("className"));
- objectData.properties = dataMap.value(_("properties")).toList();
-
- } else if (type == _("function")) {
- objectData.type = QByteArray("function");
- objectData.value = dataMap.value(_(NAME));
- objectData.properties = dataMap.value(_("properties")).toList();
-
- } else if (type == _("script")) {
- objectData.type = QByteArray("script");
- objectData.value = dataMap.value(_(NAME));
- }
- }
-
- return objectData;
-}
-
-void QmlV8DebuggerClientPrivate::clearCache()
-{
- currentFrameScopes.clear();
- updateLocalsAndWatchers.clear();
-}
-
-QByteArray QmlV8DebuggerClientPrivate::packMessage(const QByteArray &type, const QByteArray &message)
-{
- SDEBUG(message);
- QByteArray request;
- QmlDebugStream rs(&request, QIODevice::WriteOnly);
- QByteArray cmd = V8DEBUG;
- rs << cmd << type << message;
- return request;
-}
-
-QJsonObject QmlV8DebuggerClientPrivate::initObject()
-{
- return QJsonObject {
- {_(SEQ), ++sequence},
- {_(TYPE), _(REQUEST)}
- };
-}
-
-void QmlV8DebuggerClientPrivate::sendAndLogV8Request(const QJsonObject &request)
-{
- const QJsonDocument jsonMessage(request);
- logSendMessage(QString::fromLatin1("%1 %2 %3")
- .arg(_(V8DEBUG), _(V8REQUEST),
- QString::fromUtf8(jsonMessage.toJson(QJsonDocument::Compact))));
- q->sendMessage(packMessage(V8REQUEST, jsonMessage.toJson(QJsonDocument::Compact)));
-}
-
-void QmlV8DebuggerClientPrivate::logSendMessage(const QString &msg) const
-{
- if (engine)
- engine->logMessage(QLatin1String("V8DebuggerClient"), QmlEngine::LogSend, msg);
-}
-
-void QmlV8DebuggerClientPrivate::logReceiveMessage(const QString &msg) const
-{
- if (engine)
- engine->logMessage(QLatin1String("V8DebuggerClient"), QmlEngine::LogReceive, msg);
-}
-
-///////////////////////////////////////////////////////////////////////
-//
-// QmlV8DebuggerClient
-//
-///////////////////////////////////////////////////////////////////////
-
-QmlV8DebuggerClient::QmlV8DebuggerClient(QmlDebug::QmlDebugConnection *client)
- : BaseQmlDebuggerClient(client, QLatin1String("V8Debugger")),
- d(new QmlV8DebuggerClientPrivate(this))
-{
-}
-
-QmlV8DebuggerClient::~QmlV8DebuggerClient()
-{
- delete d;
-}
-
-void QmlV8DebuggerClient::startSession()
-{
- flushSendBuffer();
- d->connect();
- //Query for the V8 version. This is
- //only for logging to the debuggerlog
- d->version();
-}
-
-void QmlV8DebuggerClient::endSession()
-{
- d->disconnect();
-}
-
-void QmlV8DebuggerClient::resetSession()
-{
- clearExceptionSelection();
-}
-
-void QmlV8DebuggerClient::executeStep()
-{
- clearExceptionSelection();
- d->continueDebugging(In);
-}
-
-void QmlV8DebuggerClient::executeStepOut()
-{
- clearExceptionSelection();
- d->continueDebugging(Out);
-}
-
-void QmlV8DebuggerClient::executeNext()
-{
- clearExceptionSelection();
- d->continueDebugging(Next);
-}
-
-void QmlV8DebuggerClient::executeStepI()
-{
- clearExceptionSelection();
- d->continueDebugging(In);
-}
-
-void QmlV8DebuggerClient::executeRunToLine(const ContextData &data)
-{
- d->setBreakpoint(QString(_(SCRIPTREGEXP)), data.fileName,
- true, data.lineNumber);
- clearExceptionSelection();
- d->continueDebugging(Continue);
-}
-
-void QmlV8DebuggerClient::continueInferior()
-{
- clearExceptionSelection();
- d->continueDebugging(Continue);
-}
-
-void QmlV8DebuggerClient::interruptInferior()
-{
- d->interrupt();
-}
-
-void QmlV8DebuggerClient::activateFrame(int index)
-{
- if (index != d->engine->stackHandler()->currentIndex())
- d->frame(d->stackIndexLookup.value(index));
- d->engine->stackHandler()->setCurrentIndex(index);
-}
-
-bool QmlV8DebuggerClient::acceptsBreakpoint(Breakpoint bp)
-{
- BreakpointType type = bp.type();
- return (type == BreakpointOnQmlSignalEmit
- || type == BreakpointByFileAndLine
- || type == BreakpointAtJavaScriptThrow);
-}
-
-void QmlV8DebuggerClient::insertBreakpoint(Breakpoint bp,
- int adjustedLine,
- int adjustedColumn)
-{
- const BreakpointParameters &params = bp.parameters();
-
- if (params.type == BreakpointAtJavaScriptThrow) {
- bp.notifyBreakpointInsertOk();
- d->setExceptionBreak(AllExceptions, params.enabled);
-
- } else if (params.type == BreakpointByFileAndLine) {
- d->setBreakpoint(QString(_(SCRIPTREGEXP)), params.fileName,
- params.enabled, adjustedLine, adjustedColumn,
- QLatin1String(params.condition), params.ignoreCount);
-
- } else if (params.type == BreakpointOnQmlSignalEmit) {
- d->setBreakpoint(QString(_(EVENT)), params.functionName, params.enabled);
- bp.notifyBreakpointInsertOk();
- }
-
- d->breakpointsSync.insert(d->sequence, bp.id());
-}
-
-void QmlV8DebuggerClient::removeBreakpoint(Breakpoint bp)
-{
- const BreakpointParameters &params = bp.parameters();
-
- int breakpoint = d->breakpoints.value(bp.id());
- d->breakpoints.remove(bp.id());
-
- if (params.type == BreakpointAtJavaScriptThrow)
- d->setExceptionBreak(AllExceptions);
- else if (params.type == BreakpointOnQmlSignalEmit)
- d->setBreakpoint(QString(_(EVENT)), params.functionName, false);
- else
- d->clearBreakpoint(breakpoint);
-}
-
-void QmlV8DebuggerClient::changeBreakpoint(Breakpoint bp)
-{
- const BreakpointParameters &params = bp.parameters();
-
- BreakpointResponse br = bp.response();
- if (params.type == BreakpointAtJavaScriptThrow) {
- d->setExceptionBreak(AllExceptions, params.enabled);
- br.enabled = params.enabled;
- bp.setResponse(br);
- } else if (params.type == BreakpointOnQmlSignalEmit) {
- d->setBreakpoint(QString(_(EVENT)), params.functionName, params.enabled);
- br.enabled = params.enabled;
- bp.setResponse(br);
- } else {
- //V8 supports only minimalistic changes in breakpoint
- //Remove the breakpoint and add again
- bp.notifyBreakpointChangeOk();
- bp.removeBreakpoint();
- BreakHandler *handler = d->engine->breakHandler();
- handler->appendBreakpoint(params);
- }
-}
-
-void QmlV8DebuggerClient::synchronizeBreakpoints()
-{
- //NOT USED
-}
-
-void QmlV8DebuggerClient::assignValueInDebugger(const WatchData * /*data*/,
- const QString &expr,
- const QVariant &valueV)
-{
- StackHandler *stackHandler = d->engine->stackHandler();
- QString expression = QString(_("%1 = %2;")).arg(expr).arg(valueV.toString());
- if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
- d->evaluate(expression, false, false, stackHandler->currentIndex());
- d->updateLocalsAndWatchers.append(d->sequence);
- } else {
- d->engine->showMessage(QString(_("Cannot evaluate %1 in current stack frame")).arg(
- expression), ConsoleOutput);
- }
-}
-
-void QmlV8DebuggerClient::updateWatchData(const WatchData &/*data*/)
-{
- //NOT USED
-}
-
-void QmlV8DebuggerClient::executeDebuggerCommand(const QString &command)
-{
- StackHandler *stackHandler = d->engine->stackHandler();
- if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
- d->evaluate(command, false, false, stackHandler->currentIndex());
- d->debuggerCommands.append(d->sequence);
- } else {
- //Currently cannot evaluate if not in a javascript break
- d->engine->showMessage(QString(_("Cannot evaluate %1 in current stack frame")).arg(
- command), ConsoleOutput);
- }
-}
-
-void QmlV8DebuggerClient::synchronizeWatchers(const QStringList &watchers)
-{
- SDEBUG(watchers);
- if (d->engine->state() != InferiorStopOk)
- return;
-
- foreach (const QString &exp, watchers) {
- StackHandler *stackHandler = d->engine->stackHandler();
- if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
- d->evaluate(exp, false, false, stackHandler->currentIndex());
- d->evaluatingExpression.insert(d->sequence, exp);
- }
- }
-}
-
-void QmlV8DebuggerClient::expandObject(const QByteArray &iname, quint64 objectId)
-{
- if (objectId == 0) {
- //We may have got the global object
- const WatchItem *watch = d->engine->watchHandler()->findItem(iname);
- if (watch->value == QLatin1String("global")) {
- StackHandler *stackHandler = d->engine->stackHandler();
- if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
- d->evaluate(watch->name, false, false, stackHandler->currentIndex());
- d->evaluatingExpression.insert(d->sequence, QLatin1String(iname));
- }
- return;
- }
- }
- d->localsAndWatchers.insertMulti(objectId, iname);
- d->lookup(QList<int>() << objectId);
-}
-
-void QmlV8DebuggerClient::setEngine(QmlEngine *engine)
-{
- d->engine = engine;
- connect(this, &QmlV8DebuggerClient::stackFrameCompleted,
- engine, &QmlEngine::stackFrameCompleted);
-}
-
-void QmlV8DebuggerClient::getSourceFiles()
-{
- d->scripts(4, QList<int>(), true, QVariant());
-}
-
-void QmlV8DebuggerClient::messageReceived(const QByteArray &data)
-{
- QmlDebugStream ds(data);
- QByteArray command;
- ds >> command;
-
- if (command == V8DEBUG) {
- QByteArray type;
- QByteArray response;
- ds >> type >> response;
-
- d->logReceiveMessage(_(V8DEBUG) + QLatin1Char(' ') + QLatin1String(type));
- if (type == CONNECT) {
- //debugging session started
-
- } else if (type == INTERRUPT) {
- //debug break requested
-
- } else if (type == BREAKONSIGNAL) {
- //break on signal handler requested
-
- } else if (type == V8MESSAGE) {
- const QString responseString = QLatin1String(response);
- SDEBUG(responseString);
- d->logReceiveMessage(QLatin1String(V8MESSAGE) + QLatin1Char(' ') + responseString);
-
- const QVariantMap resp =
- QJsonDocument::fromJson(responseString.toUtf8()).toVariant().toMap();
-
- const QString type(resp.value(_(TYPE)).toString());
-
- if (type == _("response")) {
-
- bool success = resp.value(_("success")).toBool();
- if (!success) {
- SDEBUG("Request was unsuccessful");
- }
-
- const QString debugCommand(resp.value(_(COMMAND)).toString());
-
- if (debugCommand == _(DISCONNECT)) {
- //debugging session ended
-
- } else if (debugCommand == _(CONTINEDEBUGGING)) {
- //do nothing, wait for next break
-
- } else if (debugCommand == _(BACKTRACE)) {
- if (success)
- updateStack(resp.value(_(BODY)), resp.value(_(REFS)));
-
- } else if (debugCommand == _(LOOKUP)) {
- if (success)
- expandLocalsAndWatchers(resp.value(_(BODY)), resp.value(_(REFS)));
-
- } else if (debugCommand == _(EVALUATE)) {
- int seq = resp.value(_("request_seq")).toInt();
- if (success) {
- updateEvaluationResult(seq, success, resp.value(_(BODY)), resp.value(_(REFS)));
- } else {
- QVariantMap map;
- map.insert(_(TYPE), QVariant(_("string")));
- map.insert(_(VALUE), resp.value(_("message")));
- updateEvaluationResult(seq, success, QVariant(map), QVariant());
- }
-
- } else if (debugCommand == _(SETBREAKPOINT)) {
- // { "seq" : <number>,
- // "type" : "response",
- // "request_seq" : <number>,
- // "command" : "setbreakpoint",
- // "body" : { "type" : <"function" or "script">
- // "breakpoint" : <break point number of the new break point>
- // }
- // "running" : <is the VM running after sending this response>
- // "success" : true
- // }
-
- int seq = resp.value(_("request_seq")).toInt();
- const QVariantMap breakpointData = resp.value(_(BODY)).toMap();
- int index = breakpointData.value(_("breakpoint")).toInt();
-
- if (d->breakpointsSync.contains(seq)) {
- BreakpointModelId id = d->breakpointsSync.take(seq);
- d->breakpoints.insert(id, index);
-
- //Is actual position info present? Then breakpoint was
- //accepted
- const QVariantList actualLocations =
- breakpointData.value(
- _("actual_locations")).toList();
- if (actualLocations.count()) {
- //The breakpoint requested line should be same as
- //actual line
- BreakHandler *handler = d->engine->breakHandler();
- Breakpoint bp = handler->breakpointById(id);
- if (bp.state() != BreakpointInserted) {
- BreakpointResponse br = bp.response();
- br.lineNumber = breakpointData.value(_("line")).toInt() + 1;
- bp.setResponse(br);
- bp.notifyBreakpointInsertOk();
- }
- }
-
-
- } else {
- d->breakpointsTemp.append(index);
- }
-
-
- } else if (debugCommand == _(CLEARBREAKPOINT)) {
- // DO NOTHING
-
- } else if (debugCommand == _(SETEXCEPTIONBREAK)) {
- // { "seq" : <number>,
- // "type" : "response",
- // "request_seq" : <number>,
- // "command" : "setexceptionbreak",
- // "body" : { "type" : <string: "all" or "uncaught" corresponding to the request.>,
- // "enabled" : <bool: true if the break type is currently enabled as a result of the request>
- // }
- // "running" : true
- // "success" : true
- // }
-
-
- } else if (debugCommand == _(FRAME)) {
- if (success)
- setCurrentFrameDetails(resp.value(_(BODY)), resp.value(_(REFS)));
-
- } else if (debugCommand == _(SCOPE)) {
- if (success)
- updateScope(resp.value(_(BODY)), resp.value(_(REFS)));
-
- } else if (debugCommand == _(SCRIPTS)) {
- // { "seq" : <number>,
- // "type" : "response",
- // "request_seq" : <number>,
- // "command" : "scripts",
- // "body" : [ { "name" : <name of the script>,
- // "id" : <id of the script>
- // "lineOffset" : <line offset within the containing resource>
- // "columnOffset" : <column offset within the containing resource>
- // "lineCount" : <number of lines in the script>
- // "data" : <optional data object added through the API>
- // "source" : <source of the script if includeSource was specified in the request>
- // "sourceStart" : <first 80 characters of the script if includeSource was not specified in the request>
- // "sourceLength" : <total length of the script in characters>
- // "scriptType" : <script type (see request for values)>
- // "compilationType" : < How was this script compiled:
- // 0 if script was compiled through the API
- // 1 if script was compiled through eval
- // >
- // "evalFromScript" : <if "compilationType" is 1 this is the script from where eval was called>
- // "evalFromLocation" : { line : < if "compilationType" is 1 this is the line in the script from where eval was called>
- // column : < if "compilationType" is 1 this is the column in the script from where eval was called>
- // ]
- // "running" : <is the VM running after sending this response>
- // "success" : true
- // }
-
- if (success) {
- const QVariantList body = resp.value(_(BODY)).toList();
-
- QStringList sourceFiles;
- for (int i = 0; i < body.size(); ++i) {
- const QVariantMap entryMap = body.at(i).toMap();
- const int lineOffset = entryMap.value(QLatin1String("lineOffset")).toInt();
- const int columnOffset = entryMap.value(QLatin1String("columnOffset")).toInt();
- const QString name = entryMap.value(QLatin1String("name")).toString();
- const QString source = entryMap.value(QLatin1String("source")).toString();
-
- if (name.isEmpty())
- continue;
-
- if (!sourceFiles.contains(name))
- sourceFiles << name;
-
- d->engine->updateScriptSource(name, lineOffset, columnOffset, source);
- }
- d->engine->setSourceFiles(sourceFiles);
- }
- } else if (debugCommand == _(VERSION)) {
- d->logReceiveMessage(QString(_("Using V8 Version: %1")).arg(
- resp.value(_(BODY)).toMap().
- value(_("V8Version")).toString()));
-
- } else {
- // DO NOTHING
- }
-
- } else if (type == _(EVENT)) {
- const QString eventType(resp.value(_(EVENT)).toString());
-
- if (eventType == _("break")) {
- const QVariantMap breakData = resp.value(_(BODY)).toMap();
- const QString invocationText = breakData.value(_("invocationText")).toString();
- const QString scriptUrl = breakData.value(_("script")).toMap().value(_("name")).toString();
- const QString sourceLineText = breakData.value(_("sourceLineText")).toString();
-
- bool inferiorStop = true;
-
- QList<int> v8BreakpointIds;
- {
- const QVariantList v8BreakpointIdList = breakData.value(_("breakpoints")).toList();
- foreach (const QVariant &breakpointId, v8BreakpointIdList)
- v8BreakpointIds << breakpointId.toInt();
- }
-
- if (!v8BreakpointIds.isEmpty() && invocationText.startsWith(_("[anonymous]()"))
- && scriptUrl.endsWith(_(".qml"))
- && sourceLineText.trimmed().startsWith(QLatin1Char('('))) {
-
- // we hit most likely the anonymous wrapper function automatically generated for bindings
- // -> relocate the breakpoint to column: 1 and continue
-
- int newColumn = sourceLineText.indexOf(QLatin1Char('(')) + 1;
- BreakHandler *handler = d->engine->breakHandler();
-
- foreach (int v8Id, v8BreakpointIds) {
- const BreakpointModelId id = d->breakpoints.key(v8Id);
- Breakpoint bp = handler->breakpointById(id);
- if (bp.isValid()) {
- const BreakpointParameters &params = bp.parameters();
-
- d->clearBreakpoint(v8Id);
- d->setBreakpoint(QString(_(SCRIPTREGEXP)),
- params.fileName,
- params.enabled,
- params.lineNumber,
- newColumn,
- QString(QString::fromLatin1(params.condition)),
- params.ignoreCount);
- d->breakpointsSync.insert(d->sequence, id);
- }
- }
- d->continueDebugging(Continue);
- inferiorStop = false;
- }
-
- //Skip debug break if this is an internal function
- if (sourceLineText == _(INTERNAL_FUNCTION)) {
- d->continueDebugging(d->previousStepAction);
- inferiorStop = false;
- }
-
- if (inferiorStop) {
- //Update breakpoint data
- BreakHandler *handler = d->engine->breakHandler();
- foreach (int v8Id, v8BreakpointIds) {
- const BreakpointModelId id = d->breakpoints.key(v8Id);
- Breakpoint bp = handler->breakpointById(id);
- if (bp) {
- BreakpointResponse br = bp.response();
- if (br.functionName.isEmpty()) {
- br.functionName = invocationText;
- bp.setResponse(br);
- }
- if (bp.state() != BreakpointInserted) {
- br.lineNumber = breakData.value(
- _("sourceLine")).toInt() + 1;
- bp.setResponse(br);
- bp.notifyBreakpointInsertOk();
- }
- }
- }
-
- if (d->engine->state() == InferiorRunOk) {
- foreach (const QVariant &breakpointId, v8BreakpointIds) {
- if (d->breakpointsTemp.contains(breakpointId.toInt()))
- d->clearBreakpoint(breakpointId.toInt());
- }
- d->engine->inferiorSpontaneousStop();
- d->backtrace();
- } else if (d->engine->state() == InferiorStopOk) {
- d->backtrace();
- }
- }
-
- } else if (eventType == _("exception")) {
- const QVariantMap body = resp.value(_(BODY)).toMap();
- int lineNumber = body.value(_("sourceLine")).toInt() + 1;
-
- const QVariantMap script = body.value(_("script")).toMap();
- QUrl fileUrl(script.value(_(NAME)).toString());
- QString filePath = d->engine->toFileInProject(fileUrl);
-
- const QVariantMap exception = body.value(_("exception")).toMap();
- QString errorMessage = exception.value(_("text")).toString();
-
- highlightExceptionCode(lineNumber, filePath, errorMessage);
-
- if (d->engine->state() == InferiorRunOk) {
- d->engine->inferiorSpontaneousStop();
- d->backtrace();
- }
-
- if (d->engine->state() == InferiorStopOk)
- d->backtrace();
-
- } else if (eventType == _("afterCompile")) {
- //Currently break point relocation is disabled.
- //Uncomment the line below when it will be enabled.
-// d->listBreakpoints();
- }
-
- //Sometimes we do not get event type!
- //This is most probably due to a wrong eval expression.
- //Redirect output to console.
- if (eventType.isEmpty()) {
- bool success = resp.value(_("success")).toBool();
- QVariantMap map;
- map.insert(_(TYPE), QVariant(_("string")));
- map.insert(_(VALUE), resp.value(_("message")));
- //Since there is no sequence value, best estimate is
- //last sequence value
- updateEvaluationResult(d->sequence, success, QVariant(map), QVariant());
- }
-
- } //EVENT
- } //V8MESSAGE
-
- } else {
- //DO NOTHING
- }
-}
-
-void QmlV8DebuggerClient::updateStack(const QVariant &bodyVal, const QVariant &refsVal)
-{
- // { "seq" : <number>,
- // "type" : "response",
- // "request_seq" : <number>,
- // "command" : "backtrace",
- // "body" : { "fromFrame" : <number>
- // "toFrame" : <number>
- // "totalFrames" : <number>
- // "frames" : <array of frames - see frame request for details>
- // }
- // "running" : <is the VM running after sending this response>
- // "success" : true
- // }
-
- const QVariantMap body = bodyVal.toMap();
- const QVariantList frames = body.value(_("frames")).toList();
-
- int fromFrameIndex = body.value(_("fromFrame")).toInt();
-
- QTC_ASSERT(0 == fromFrameIndex, return);
-
- StackHandler *stackHandler = d->engine->stackHandler();
- StackFrames stackFrames;
- int i = 0;
- d->stackIndexLookup.clear();
- foreach (const QVariant &frame, frames) {
- StackFrame stackFrame = extractStackFrame(frame, refsVal);
- if (stackFrame.level < 0)
- continue;
- d->stackIndexLookup.insert(i, stackFrame.level);
- stackFrame.level = i;
- stackFrames << stackFrame;
- i++;
- }
- stackHandler->setFrames(stackFrames);
-
- //Populate locals and watchers wrt top frame
- //Update all Locals visible in current scope
- //Traverse the scope chain and store the local properties
- //in a list and show them in the Locals Window.
- setCurrentFrameDetails(frames.value(0), refsVal);
-}
-
-StackFrame QmlV8DebuggerClient::extractStackFrame(const QVariant &bodyVal, const QVariant &refsVal)
-{
- // { "seq" : <number>,
- // "type" : "response",
- // "request_seq" : <number>,
- // "command" : "frame",
- // "body" : { "index" : <frame number>,
- // "receiver" : <frame receiver>,
- // "func" : <function invoked>,
- // "script" : <script for the function>,
- // "constructCall" : <boolean indicating whether the function was called as constructor>,
- // "debuggerFrame" : <boolean indicating whether this is an internal debugger frame>,
- // "arguments" : [ { name: <name of the argument - missing of anonymous argument>,
- // value: <value of the argument>
- // },
- // ... <the array contains all the arguments>
- // ],
- // "locals" : [ { name: <name of the local variable>,
- // value: <value of the local variable>
- // },
- // ... <the array contains all the locals>
- // ],
- // "position" : <source position>,
- // "line" : <source line>,
- // "column" : <source column within the line>,
- // "sourceLineText" : <text for current source line>,
- // "scopes" : [ <array of scopes, see scope request below for format> ],
-
- // }
- // "running" : <is the VM running after sending this response>
- // "success" : true
- // }
-
- const QVariantMap body = bodyVal.toMap();
-
- StackFrame stackFrame;
- stackFrame.level = body.value(_("index")).toInt();
- //Do not insert the frame corresponding to the internal function
- if (body.value(QLatin1String("sourceLineText")) == QLatin1String(INTERNAL_FUNCTION)) {
- stackFrame.level = -1;
- return stackFrame;
- }
-
- QmlV8ObjectData objectData = extractData(body.value(_("func")), refsVal);
- QString functionName = objectData.value.toString();
- if (functionName.isEmpty())
- functionName = tr("Anonymous Function");
- stackFrame.function = functionName;
-
- objectData = extractData(body.value(_("script")), refsVal);
- stackFrame.file = d->engine->toFileInProject(objectData.value.toString());
- stackFrame.usable = QFileInfo(stackFrame.file).isReadable();
-
- objectData = extractData(body.value(_("receiver")), refsVal);
- stackFrame.to = objectData.value.toString();
-
- stackFrame.line = body.value(_("line")).toInt() + 1;
-
- return stackFrame;
-}
-
-void QmlV8DebuggerClient::setCurrentFrameDetails(const QVariant &bodyVal, const QVariant &refsVal)
-{
- // { "seq" : <number>,
- // "type" : "response",
- // "request_seq" : <number>,
- // "command" : "frame",
- // "body" : { "index" : <frame number>,
- // "receiver" : <frame receiver>,
- // "func" : <function invoked>,
- // "script" : <script for the function>,
- // "constructCall" : <boolean indicating whether the function was called as constructor>,
- // "debuggerFrame" : <boolean indicating whether this is an internal debugger frame>,
- // "arguments" : [ { name: <name of the argument - missing of anonymous argument>,
- // value: <value of the argument>
- // },
- // ... <the array contains all the arguments>
- // ],
- // "locals" : [ { name: <name of the local variable>,
- // value: <value of the local variable>
- // },
- // ... <the array contains all the locals>
- // ],
- // "position" : <source position>,
- // "line" : <source line>,
- // "column" : <source column within the line>,
- // "sourceLineText" : <text for current source line>,
- // "scopes" : [ <array of scopes, see scope request below for format> ],
-
- // }
- // "running" : <is the VM running after sending this response>
- // "success" : true
- // }
- QVariantMap currentFrame = bodyVal.toMap();
-
- StackHandler *stackHandler = d->engine->stackHandler();
- WatchHandler * watchHandler = d->engine->watchHandler();
- watchHandler->notifyUpdateStarted();
- d->clearCache();
-
- const int frameIndex = stackHandler->currentIndex();
- QSet<QByteArray> expandedInames = watchHandler->expandedINames();
- QHash<quint64, QByteArray> handlesToLookup;
- // Store handles of all expanded watch data
- foreach (const QByteArray &iname, expandedInames) {
- const WatchItem *item = watchHandler->findItem(iname);
- if (item && item->isLocal())
- handlesToLookup.insert(item->id, iname);
- }
- if (frameIndex < 0)
- return;
- const StackFrame frame = stackHandler->currentFrame();
- if (!frame.isUsable())
- return;
-
- //Set "this" variable
- {
- auto item = new WatchItem("local.this", QLatin1String("this"));
- QmlV8ObjectData objectData = extractData(currentFrame.value(_("receiver")), refsVal);
- item->id = objectData.handle;
- item->type = objectData.type;
- item->value = objectData.value.toString();
- item->setHasChildren(objectData.properties.count());
- //Incase of global object, we do not get children
- //Set children nevertheless and query later
- if (item->value == QLatin1String("global")) {
- item->setHasChildren(true);
- item->id = 0;
- }
- watchHandler->insertItem(item);
- }
-
- const QVariantList currentFrameScopes = currentFrame.value(_("scopes")).toList();
- foreach (const QVariant &scope, currentFrameScopes) {
- //Do not query for global types (0)
- //Showing global properties increases clutter.
- if (scope.toMap().value(_("type")).toInt() == 0)
- continue;
- int scopeIndex = scope.toMap().value(_("index")).toInt();
- d->currentFrameScopes.append(scopeIndex);
- d->scope(scopeIndex);
- }
- d->engine->gotoLocation(stackHandler->currentFrame());
-
- // Expand watch data that were previously expanded
- QHash<quint64, QByteArray>::const_iterator itEnd = handlesToLookup.constEnd();
- for (QHash<quint64, QByteArray>::const_iterator it = handlesToLookup.constBegin(); it != itEnd; ++it)
- expandObject(it.value(), it.key());
- emit stackFrameCompleted();
-}
-
-void QmlV8DebuggerClient::updateScope(const QVariant &bodyVal, const QVariant &refsVal)
-{
-// { "seq" : <number>,
-// "type" : "response",
-// "request_seq" : <number>,
-// "command" : "scope",
-// "body" : { "index" : <index of this scope in the scope chain. Index 0 is the top scope
-// and the global scope will always have the highest index for a
-// frame>,
-// "frameIndex" : <index of the frame>,
-// "type" : <type of the scope:
-// 0: Global
-// 1: Local
-// 2: With
-// 3: Closure
-// 4: Catch >,
-// "object" : <the scope object defining the content of the scope.
-// For local and closure scopes this is transient objects,
-// which has a negative handle value>
-// }
-// "running" : <is the VM running after sending this response>
-// "success" : true
-// }
- QVariantMap bodyMap = bodyVal.toMap();
-
- //Check if the frameIndex is same as current Stack Index
- StackHandler *stackHandler = d->engine->stackHandler();
- if (bodyMap.value(_("frameIndex")).toInt() != stackHandler->currentIndex())
- return;
-
- QmlV8ObjectData objectData = extractData(bodyMap.value(_("object")), refsVal);
-
- QList<int> handlesToLookup;
- foreach (const QVariant &property, objectData.properties) {
- QmlV8ObjectData localData = extractData(property, refsVal);
- auto item = new WatchItem;
- item->exp = localData.name;
- //Check for v8 specific local data
- if (item->exp.startsWith('.') || item->exp.isEmpty())
- continue;
-
- item->name = QLatin1String(item->exp);
- item->iname = QByteArray("local.") + item->exp;
-
- int handle = localData.handle;
- if (localData.value.isValid()) {
- item->id = handle;
- item->type = localData.type;
- item->value = localData.value.toString();
- item->setHasChildren(localData.properties.count());
- d->engine->watchHandler()->insertItem(item);
- } else {
- handlesToLookup << handle;
- d->localsAndWatchers.insertMulti(handle, item->exp);
- }
- }
-
- if (!handlesToLookup.isEmpty())
- d->lookup(handlesToLookup);
- else
- d->engine->watchHandler()->notifyUpdateFinished();
-}
-
-QmlJS::ConsoleItem *constructLogItemTree(QmlJS::ConsoleItem *parent,
- const QmlV8ObjectData &objectData,
- const QVariant &refsVal)
-{
- using namespace QmlJS;
- bool sorted = boolSetting(SortStructMembers);
- if (!objectData.value.isValid())
- return 0;
-
- QString text;
- if (objectData.name.isEmpty())
- text = objectData.value.toString();
- else
- text = QString(_("%1: %2")).arg(QString::fromLatin1(objectData.name))
- .arg(objectData.value.toString());
-
- ConsoleItem *item = new ConsoleItem(parent, ConsoleItem::UndefinedType, text);
-
- QSet<QString> childrenFetched;
- foreach (const QVariant &property, objectData.properties) {
- const QmlV8ObjectData childObjectData = extractData(property, refsVal);
- if (childObjectData.handle == objectData.handle)
- continue;
- ConsoleItem *child = constructLogItemTree(item, childObjectData, refsVal);
- if (child) {
- const QString text = child->text();
- if (childrenFetched.contains(text))
- continue;
- childrenFetched.insert(text);
- item->insertChild(child, sorted);
- }
- }
-
- return item;
-}
-
-void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success,
- const QVariant &bodyVal, const QVariant &refsVal)
-{
- // { "seq" : <number>,
- // "type" : "response",
- // "request_seq" : <number>,
- // "command" : "evaluate",
- // "body" : ...
- // "running" : <is the VM running after sending this response>
- // "success" : true
- // }
- WatchHandler *watchHandler = d->engine->watchHandler();
- if (d->updateLocalsAndWatchers.contains(sequence)) {
- d->updateLocalsAndWatchers.removeOne(sequence);
- //Update the locals
- foreach (int index, d->currentFrameScopes)
- d->scope(index);
- //Also update "this"
- QByteArray iname("local.this");
- const WatchItem *parent = watchHandler->findItem(iname);
- d->localsAndWatchers.insertMulti(parent->id, iname);
- d->lookup(QList<int>() << parent->id);
-
- } else if (d->debuggerCommands.contains(sequence)) {
- d->updateLocalsAndWatchers.removeOne(sequence);
- QmlV8ObjectData body = extractData(bodyVal, refsVal);
- using namespace QmlJS;
- ConsoleManagerInterface *consoleManager = ConsoleManagerInterface::instance();
- if (consoleManager) {
- ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), body, refsVal);
- if (item)
- consoleManager->printToConsolePane(item);
- }
- //Update the locals
- foreach (int index, d->currentFrameScopes)
- d->scope(index);
-
- } else {
- QmlV8ObjectData body = extractData(bodyVal, refsVal);
- if (d->evaluatingExpression.contains(sequence)) {
- QString exp = d->evaluatingExpression.take(sequence);
- //Do we have request to evaluate a local?
- if (exp.startsWith(QLatin1String("local."))) {
- const WatchItem *item = watchHandler->findItem(exp.toLatin1());
- createWatchDataList(item, body.properties, refsVal);
- } else {
- QByteArray iname = watchHandler->watcherName(exp.toLatin1());
- SDEBUG(QString(iname));
-
- auto item = new WatchItem(iname, exp);
- item->exp = exp.toLatin1();
- item->id = body.handle;
- if (success) {
- item->type = body.type;
- item->value = body.value.toString();
- item->wantsChildren = body.properties.count();
- } else {
- //Do not set type since it is unknown
- item->setError(body.value.toString());
- }
- watchHandler->insertItem(item);
- createWatchDataList(item, body.properties, refsVal);
- }
- //Insert the newly evaluated expression to the Watchers Window
- }
- }
-}
-
-void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const QVariant &refsVal)
-{
- // { "seq" : <number>,
- // "type" : "response",
- // "request_seq" : <number>,
- // "command" : "lookup",
- // "body" : <array of serialized objects indexed using their handle>
- // "running" : <is the VM running after sending this response>
- // "success" : true
- // }
- const QVariantMap body = bodyVal.toMap();
-
- QStringList handlesList = body.keys();
- WatchHandler *watchHandler = d->engine->watchHandler();
- foreach (const QString &handle, handlesList) {
- QmlV8ObjectData bodyObjectData = extractData(
- body.value(handle), refsVal);
- QByteArray prepend = d->localsAndWatchers.take(handle.toInt());
-
- if (prepend.startsWith("local.") || prepend.startsWith("watch.")) {
- // Data for expanded local/watch.
- // Could be an object or function.
- const WatchItem *parent = watchHandler->findItem(prepend);
- createWatchDataList(parent, bodyObjectData.properties, refsVal);
- } else {
- //rest
- auto item = new WatchItem;
- item->exp = prepend;
- item->name = QLatin1String(item->exp);
- item->iname = QByteArray("local.") + item->exp;
- item->id = handle.toInt();
-
- item->type = bodyObjectData.type;
- item->value = bodyObjectData.value.toString();
-
- item->setHasChildren(bodyObjectData.properties.count());
-
- d->engine->watchHandler()->insertItem(item);
- }
- }
- d->engine->watchHandler()->notifyUpdateFinished();
-}
-
-void QmlV8DebuggerClient::createWatchDataList(const WatchItem *parent,
- const QVariantList &properties,
- const QVariant &refsVal)
-{
- if (properties.count()) {
- QTC_ASSERT(parent, return);
- foreach (const QVariant &property, properties) {
- QmlV8ObjectData propertyData = extractData(property, refsVal);
- auto item = new WatchItem;
- item->name = QString::fromUtf8(propertyData.name);
-
- //Check for v8 specific local data
- if (item->name.startsWith(QLatin1Char('.')) || item->name.isEmpty())
- continue;
- if (parent->type == "object") {
- if (parent->value == _("Array"))
- item->exp = parent->exp + '[' + item->name.toLatin1() + ']';
- else if (parent->value == _("Object"))
- item->exp = parent->exp + '.' + item->name.toLatin1();
- } else {
- item->exp = item->name.toLatin1();
- }
-
- item->iname = parent->iname + '.' + item->name.toLatin1();
- item->id = propertyData.handle;
- item->type = propertyData.type;
- item->value = propertyData.value.toString();
- item->setHasChildren(propertyData.properties.count());
- d->engine->watchHandler()->insertItem(item);
- }
- }
-}
-
-void QmlV8DebuggerClient::highlightExceptionCode(int lineNumber,
- const QString &filePath,
- const QString &errorMessage)
-{
- QList<IEditor *> editors = DocumentModel::editorsForFilePath(filePath);
-
- // set up the format for the errors
- QTextCharFormat errorFormat;
- errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
- errorFormat.setUnderlineColor(Qt::red);
-
- foreach (IEditor *editor, editors) {
- TextEditor::TextEditorWidget *ed = qobject_cast<TextEditor::TextEditorWidget *>(editor->widget());
- if (!ed)
- continue;
-
- QList<QTextEdit::ExtraSelection> selections;
- QTextEdit::ExtraSelection sel;
- sel.format = errorFormat;
- QTextCursor c(ed->document()->findBlockByNumber(lineNumber - 1));
- const QString text = c.block().text();
- for (int i = 0; i < text.size(); ++i) {
- if (! text.at(i).isSpace()) {
- c.setPosition(c.position() + i);
- break;
- }
- }
- c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
- sel.cursor = c;
-
- sel.format.setToolTip(errorMessage);
-
- selections.append(sel);
- ed->setExtraSelections(TextEditor::TextEditorWidget::DebuggerExceptionSelection, selections);
-
- QString message = QString(_("%1: %2: %3")).arg(filePath).arg(lineNumber)
- .arg(errorMessage);
- d->engine->showMessage(message, ConsoleOutput);
- }
-}
-
-void QmlV8DebuggerClient::clearExceptionSelection()
-{
- QList<QTextEdit::ExtraSelection> selections;
-
- foreach (IEditor *editor, DocumentModel::editorsForOpenedDocuments()) {
- TextEditor::TextEditorWidget *ed = qobject_cast<TextEditor::TextEditorWidget *>(editor->widget());
- if (!ed)
- continue;
-
- ed->setExtraSelections(TextEditor::TextEditorWidget::DebuggerExceptionSelection, selections);
- }
-
-}
-
-} // Internal
-} // Debugger
diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.h b/src/plugins/debugger/qml/qmlv8debuggerclient.h
deleted file mode 100644
index ae78443e77..0000000000
--- a/src/plugins/debugger/qml/qmlv8debuggerclient.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef QMLV8DEBUGGERCLIENT_H
-#define QMLV8DEBUGGERCLIENT_H
-
-#include "baseqmldebuggerclient.h"
-
-namespace Debugger {
-namespace Internal {
-
-class QmlV8DebuggerClientPrivate;
-
-class QmlV8DebuggerClient : public BaseQmlDebuggerClient
-{
- Q_OBJECT
-
- enum Exceptions
- {
- NoExceptions,
- UncaughtExceptions,
- AllExceptions
- };
-
- enum StepAction
- {
- Continue,
- In,
- Out,
- Next
- };
-
-public:
- explicit QmlV8DebuggerClient(QmlDebug::QmlDebugConnection *client);
- ~QmlV8DebuggerClient();
-
- void startSession();
- void endSession();
- void resetSession();
-
- void executeStep();
- void executeStepOut();
- void executeNext();
- void executeStepI();
-
- void executeRunToLine(const ContextData &data);
-
- void continueInferior();
- void interruptInferior();
-
- void activateFrame(int index);
-
- bool acceptsBreakpoint(Breakpoint bp);
- void insertBreakpoint(Breakpoint bp, int adjustedLine,
- int adjustedColumn = -1);
- void removeBreakpoint(Breakpoint bp);
- void changeBreakpoint(Breakpoint bp);
- void synchronizeBreakpoints();
-
- void assignValueInDebugger(const WatchData *data,
- const QString &expression,
- const QVariant &valueV);
-
- void updateWatchData(const WatchData &);
- void executeDebuggerCommand(const QString &command);
-
- void synchronizeWatchers(const QStringList &watchers);
-
- void expandObject(const QByteArray &iname, quint64 objectId);
-
- void setEngine(QmlEngine *engine);
-
- void getSourceFiles();
-
-protected:
- void messageReceived(const QByteArray &data);
-
-private:
- void updateStack(const QVariant &bodyVal, const QVariant &refsVal);
- StackFrame extractStackFrame(const QVariant &bodyVal, const QVariant &refsVal);
- void setCurrentFrameDetails(const QVariant &bodyVal, const QVariant &refsVal);
- void updateScope(const QVariant &bodyVal, const QVariant &refsVal);
-
- void updateEvaluationResult(int sequence, bool success, const QVariant &bodyVal,
- const QVariant &refsVal);
- void expandLocalsAndWatchers(const QVariant &bodyVal, const QVariant &refsVal);
- void createWatchDataList(const WatchItem *parent,
- const QVariantList &properties,
- const QVariant &refsVal);
-
- void highlightExceptionCode(int lineNumber, const QString &filePath,
- const QString &errorMessage);
- void clearExceptionSelection();
-
-private:
- QmlV8DebuggerClientPrivate *d;
- friend class QmlV8DebuggerClientPrivate;
-};
-
-} // Internal
-} // Debugger
-
-#endif // QMLV8DEBUGGERCLIENT_H
diff --git a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
deleted file mode 100644
index fd9b246557..0000000000
--- a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
+++ /dev/null
@@ -1,606 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-#include "qscriptdebuggerclient.h"
-
-#include "qmlengine.h"
-#include <debugger/watchhandler.h>
-#include <debugger/breakhandler.h>
-#include <debugger/stackhandler.h>
-#include <debugger/debuggercore.h>
-#include <debugger/debuggerstringutils.h>
-#include <qmldebug/qmldebugclient.h>
-
-#include <coreplugin/messagebox.h>
-
-#include <QFileInfo>
-#include <utils/qtcassert.h>
-
-using QmlDebug::QmlDebugStream;
-
-namespace Debugger {
-namespace Internal {
-
-struct JSAgentBreakpointData
-{
- QByteArray functionName;
- QByteArray fileUrl;
- qint32 lineNumber;
-};
-
-struct JSAgentStackData
-{
- QByteArray functionName;
- QByteArray fileUrl;
- qint32 lineNumber;
-};
-
-uint qHash(const JSAgentBreakpointData &b)
-{
- return b.lineNumber ^ qHash(b.fileUrl);
-}
-
-QDataStream &operator<<(QDataStream &s, const JSAgentBreakpointData &data)
-{
- return s << data.functionName << data.fileUrl << data.lineNumber;
-}
-
-QDataStream &operator<<(QDataStream &s, const JSAgentStackData &data)
-{
- return s << data.functionName << data.fileUrl << data.lineNumber;
-}
-
-QDataStream &operator>>(QDataStream &s, JSAgentBreakpointData &data)
-{
- return s >> data.functionName >> data.fileUrl >> data.lineNumber;
-}
-
-QDataStream &operator>>(QDataStream &s, JSAgentStackData &data)
-{
- return s >> data.functionName >> data.fileUrl >> data.lineNumber;
-}
-
-bool operator==(const JSAgentBreakpointData &b1, const JSAgentBreakpointData &b2)
-{
- return b1.lineNumber == b2.lineNumber && b1.fileUrl == b2.fileUrl;
-}
-
-typedef QSet<JSAgentBreakpointData> JSAgentBreakpoints;
-typedef QList<JSAgentStackData> JSAgentStackFrames;
-
-
-static QDataStream &operator>>(QDataStream &s, WatchData &data)
-{
- data = WatchData();
- QByteArray name;
- QByteArray value;
- QByteArray type;
- bool hasChildren = false;
- s >> data.exp >> name >> value >> type >> hasChildren >> data.id;
- data.name = QString::fromUtf8(name);
- data.setType(type, false);
- data.setValue(QString::fromUtf8(value));
- data.setHasChildren(hasChildren);
- data.setAllUnneeded();
- return s;
-}
-
-class QScriptDebuggerClientPrivate
-{
-public:
- explicit QScriptDebuggerClientPrivate(QScriptDebuggerClient *) :
- ping(0), sessionStarted(false), engine(0)
- {
-
- }
-
- int ping;
- bool sessionStarted;
- QmlEngine *engine;
- JSAgentBreakpoints breakpoints;
-
- void logSendMessage(const QString &msg) const;
- void logReceiveMessage(const QString &msg) const;
-};
-
-QScriptDebuggerClient::QScriptDebuggerClient(QmlDebug::QmlDebugConnection* client)
- : BaseQmlDebuggerClient(client, QLatin1String("JSDebugger")),
- d(new QScriptDebuggerClientPrivate(this))
-{
-}
-
-QScriptDebuggerClient::~QScriptDebuggerClient()
-{
- delete d;
-}
-
-void QScriptDebuggerClient::executeStep()
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "STEPINTO";
- rs << cmd;
- d->logSendMessage(QLatin1String(cmd));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::executeStepOut()
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "STEPOUT";
- rs << cmd;
- d->logSendMessage(QLatin1String(cmd));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::executeNext()
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "STEPOVER";
- rs << cmd;
- d->logSendMessage(QLatin1String(cmd));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::executeStepI()
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "STEPINTO";
- rs << cmd;
- d->logSendMessage(QLatin1String(cmd));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::executeRunToLine(const ContextData &data)
-{
- JSAgentBreakpointData bp;
- bp.fileUrl = QUrl::fromLocalFile(data.fileName).toString().toUtf8();
- bp.lineNumber = data.lineNumber;
- bp.functionName = "TEMPORARY";
- d->breakpoints.insert(bp);
- synchronizeBreakpoints();
- continueInferior();
-}
-
-void QScriptDebuggerClient::continueInferior()
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "CONTINUE";
- rs << cmd;
- d->logSendMessage(QLatin1String(cmd));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::interruptInferior()
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "INTERRUPT";
- rs << cmd;
- d->logSendMessage(QLatin1String(cmd));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::startSession()
-{
- //Flush buffered data
- flushSendBuffer();
-
- //Set all breakpoints
- BreakHandler *handler = d->engine->breakHandler();
- DebuggerEngine * engine = d->engine->isSlaveEngine() ?
- d->engine->masterEngine() : d->engine;
- foreach (Breakpoint bp, handler->engineBreakpoints(engine)) {
- QTC_CHECK(bp.state() == BreakpointInsertProceeding);
- bp.notifyBreakpointInsertOk();
- }
- d->sessionStarted = true;
-}
-
-void QScriptDebuggerClient::endSession()
-{
-}
-
-void QScriptDebuggerClient::resetSession()
-{
- d->sessionStarted = false;
-}
-
-void QScriptDebuggerClient::activateFrame(int index)
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "ACTIVATE_FRAME";
- rs << cmd
- << index;
- d->logSendMessage(QLatin1String(cmd) + QLatin1Char(' ') + QString::number(index));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::insertBreakpoint(Breakpoint bp,
- int adjustedLine,
- int /*adjustedColumn*/)
-{
- JSAgentBreakpointData jsbp;
- jsbp.fileUrl = QUrl::fromLocalFile(bp.fileName()).toString().toUtf8();
- jsbp.lineNumber = adjustedLine;
- jsbp.functionName = bp.functionName().toUtf8();
- d->breakpoints.insert(jsbp);
-
- BreakpointResponse br = bp.response();
- br.lineNumber = adjustedLine;
- bp.setResponse(br);
- if (d->sessionStarted && bp.state() == BreakpointInsertProceeding)
- bp.notifyBreakpointInsertOk();
-}
-
-void QScriptDebuggerClient::removeBreakpoint(Breakpoint bp)
-{
- JSAgentBreakpointData jsbp;
- jsbp.fileUrl = QUrl::fromLocalFile(bp.fileName()).toString().toUtf8();
- jsbp.lineNumber = bp.lineNumber();
- jsbp.functionName = bp.functionName().toUtf8();
- d->breakpoints.remove(jsbp);
-}
-
-void QScriptDebuggerClient::changeBreakpoint(Breakpoint bp)
-{
- if (bp.isEnabled())
- insertBreakpoint(bp, bp.response().lineNumber);
- else
- removeBreakpoint(bp);
-
- BreakpointResponse br = bp.response();
- br.enabled = bp.isEnabled();
- bp.setResponse(br);
-}
-
-void QScriptDebuggerClient::synchronizeBreakpoints()
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "BREAKPOINTS";
- rs << cmd
- << d->breakpoints;
-
- QString logBreakpoints;
- QTextStream str(&logBreakpoints);
- str << cmd << " (";
- bool first = true;
- foreach (const JSAgentBreakpointData &bp, d->breakpoints) {
- if (first)
- first = false;
- else
- str << ", ";
- str << '[' << bp.functionName << ", " << bp.fileUrl << ", " << bp.lineNumber << ']';
- }
- str << ')';
- d->logSendMessage(logBreakpoints);
-
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::assignValueInDebugger(const WatchData *data,
- const QString &expr,
- const QVariant &valueV)
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "EXEC";
- rs << cmd;
- QString expression = QString(_("%1 = %2;")).arg(expr).arg(valueV.toString());
- rs << data->iname << expression;
- d->logSendMessage(QString::fromLatin1("%1 %2 %3 %4").
- arg(QLatin1String(cmd), QLatin1String(data->iname), expr,
- valueV.toString()));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::updateWatchData(const WatchData &data)
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "EXEC";
- rs << cmd;
- rs << data.iname << data.name;
- d->logSendMessage(QLatin1String(cmd) + QLatin1Char(' ') + QLatin1String(data.iname)
- + QLatin1Char(' ') + data.name);
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::executeDebuggerCommand(const QString &command)
-{
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "EXEC";
- QByteArray console = "console";
- rs << cmd << console << command;
- d->logSendMessage(QLatin1String(cmd) + QLatin1Char(' ') + QLatin1String(console)
- + QLatin1Char(' ') + command);
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::synchronizeWatchers(const QStringList &watchers)
-{
- // send watchers list
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "WATCH_EXPRESSIONS";
- rs << cmd;
- d->logSendMessage(QString::fromLatin1("%1 (%2)").arg(QLatin1String(cmd),
- watchers.join(QLatin1String(", "))));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::expandObject(const QByteArray &iname, quint64 objectId)
-{
- //Check if id is valid
- if (qint64(objectId) == -1)
- return;
-
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "EXPAND";
- rs << cmd;
- rs << iname << objectId;
- d->logSendMessage(QLatin1String(cmd) + QLatin1Char(' ') + QLatin1String(iname)
- + QString::number(objectId));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::sendPing()
-{
- d->ping++;
- QByteArray reply;
- QmlDebugStream rs(&reply, QIODevice::WriteOnly);
- QByteArray cmd = "PING";
- rs << cmd;
- rs << d->ping;
- d->logSendMessage(QLatin1String(cmd));
- sendMessage(reply);
-}
-
-void QScriptDebuggerClient::messageReceived(const QByteArray &data)
-{
- QByteArray rwData = data;
- QmlDebugStream stream(&rwData, QIODevice::ReadOnly);
-
- QByteArray command;
- stream >> command;
-
- WatchHandler *watchHandler = d->engine->watchHandler();
- StackHandler *stackHandler = d->engine->stackHandler();
-
- if (command == "STOPPED") {
- d->engine->inferiorSpontaneousStop();
-
- QString logString = QString::fromLatin1(command);
-
- JSAgentStackFrames stackFrames;
- QList<WatchData> watches;
- QList<WatchData> locals;
- stream >> stackFrames >> watches >> locals;
-
- logString += QString::fromLatin1(" (%1 stack frames) (%2 watches) (%3 locals)").
- arg(stackFrames.size()).arg(watches.size()).arg(locals.size());
-
- StackFrames ideStackFrames;
- for (int i = 0; i != stackFrames.size(); ++i) {
- StackFrame frame;
- frame.line = stackFrames.at(i).lineNumber;
- frame.function = QLatin1String(stackFrames.at(i).functionName);
- frame.file = d->engine->toFileInProject(QUrl(QLatin1String(stackFrames.at(i).fileUrl)));
- frame.usable = QFileInfo(frame.file).isReadable();
- frame.level = i + 1;
- ideStackFrames << frame;
- }
-
- stackHandler->setFrames(ideStackFrames);
-
- bool becauseOfException;
- stream >> becauseOfException;
-
- logString += becauseOfException ? QLatin1String(" exception") : QLatin1String(" no_exception");
-
- if (becauseOfException) {
- QString error;
- stream >> error;
-
- logString += QLatin1Char(' ');
- logString += error;
- d->logReceiveMessage(logString);
-
- QString msg = stackFrames.isEmpty()
- ? tr("<p>An uncaught exception occurred:</p><p>%1</p>")
- .arg(error.toHtmlEscaped())
- : tr("<p>An uncaught exception occurred in \"%1\":</p><p>%2</p>")
- .arg(QLatin1String(stackFrames.value(0).fileUrl), error.toHtmlEscaped());
- Core::AsynchronousMessageBox::information(tr("Uncaught Exception"), msg);
- } else {
- QString file;
- int line = -1;
-
- if (!ideStackFrames.isEmpty()) {
- file = ideStackFrames.at(0).file;
- line = ideStackFrames.at(0).line;
- }
-
- QList<JSAgentBreakpointData> breakpoints(d->breakpoints.toList());
- foreach (const JSAgentBreakpointData &data, breakpoints) {
- if (data.fileUrl == QUrl::fromLocalFile(file).toString().toUtf8() &&
- data.lineNumber == line &&
- data.functionName == "TEMPORARY") {
- breakpoints.removeOne(data);
- d->breakpoints = JSAgentBreakpoints::fromList(breakpoints);
- synchronizeBreakpoints();
- break;
- }
- }
-
- d->logReceiveMessage(logString);
- }
-
- if (!ideStackFrames.isEmpty())
- d->engine->gotoLocation(ideStackFrames.value(0));
-
- insertLocalsAndWatches(locals, watches, stackHandler->currentIndex());
-
- } else if (command == "RESULT") {
- WatchData data;
- QByteArray iname;
- stream >> iname >> data;
-
- d->logReceiveMessage(QLatin1String(command) + QLatin1Char(' ')
- + QLatin1String(iname) + QLatin1Char(' ') + data.value);
-
- auto item = new WatchItem(data);
- item->iname = iname;
- if (iname.startsWith("watch.")) {
- watchHandler->insertItem(item);
- } else if (iname == "console") {
- d->engine->showMessage(item->value, ConsoleOutput);
- } else if (iname.startsWith("local.")) {
- item->name = item->name.left(item->name.indexOf(QLatin1Char(' ')));
- watchHandler->insertItem(item);
- } else {
- qWarning() << "QmlEngine: Unexcpected result: " << iname << item->value;
- }
- } else if (command == "EXPANDED") {
- QList<WatchData> result;
- QByteArray iname;
- stream >> iname >> result;
- d->logReceiveMessage(QString::fromLatin1("%1 %2 (%3 x watchdata)").
- arg(QLatin1String(command), QLatin1String(iname),
- QString::number(result.size())));
- bool needPing = false;
-
- foreach (WatchData data, result) {
- data.iname = iname + '.' + data.exp;
- watchHandler->insertItem(new WatchItem(data));
-
- if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
- needPing = true;
- expandObject(data.iname, data.id);
- }
- }
- if (needPing)
- sendPing();
- } else if (command == "LOCALS") {
- QList<WatchData> locals;
- QList<WatchData> watches;
- int frameId;
- stream >> frameId >> locals;
- if (!stream.atEnd()) { // compatibility with jsdebuggeragent from 2.1, 2.2
- stream >> watches;
- }
-
- d->logReceiveMessage(QString::fromLatin1("%1 %2 (%3 x locals) (%4 x watchdata)").arg(
- QLatin1String(command), QString::number(frameId),
- QString::number(locals.size()), QString::number(watches.size())));
-
- insertLocalsAndWatches(locals, watches, frameId);
-
- } else if (command == "PONG") {
- int ping;
- stream >> ping;
- d->logReceiveMessage(QLatin1String(command) + QLatin1Char(' ') + QString::number(ping));
- } else {
- qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
- d->logReceiveMessage(QLatin1String(command) + QLatin1String(" UNKNOWN COMMAND!!"));
- }
-
-}
-
-void QScriptDebuggerClient::insertLocalsAndWatches(QList<WatchData> &locals,
- QList<WatchData> &watches,
- int stackFrameIndex)
-{
- WatchHandler *watchHandler = d->engine->watchHandler();
- watchHandler->removeAllData();
- if (stackFrameIndex < 0)
- return;
- const StackFrame frame = d->engine->stackHandler()->frameAt(stackFrameIndex);
- if (!frame.isUsable())
- return;
-
- bool needPing = false;
- foreach (const WatchData &data, watches) {
- auto item = new WatchItem(data);
- item->iname = watchHandler->watcherName(data.exp);
- watchHandler->insertItem(item);
-
- if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
- needPing = true;
- expandObject(data.iname, data.id);
- }
- }
-
- foreach (const WatchData &data, locals) {
- auto item = new WatchItem(data);
- if (item->name == QLatin1String("<no initialized data>"))
- item->name = tr("No Local Variables");
- item->iname = "local." + item->exp;
- watchHandler->insertItem(item);
-
- if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
- needPing = true;
- expandObject(data.iname, data.id);
- }
- }
-
- if (needPing)
- sendPing();
- emit stackFrameCompleted();
-}
-
-void QScriptDebuggerClient::setEngine(QmlEngine *engine)
-{
- d->engine = engine;
- connect(this, &QScriptDebuggerClient::stackFrameCompleted,
- engine, &DebuggerEngine::stackFrameCompleted);
-}
-
-void QScriptDebuggerClientPrivate::logSendMessage(const QString &msg) const
-{
- if (engine)
- engine->logMessage(QLatin1String("QScriptDebuggerClient"), QmlEngine::LogSend, msg);
-}
-
-void QScriptDebuggerClientPrivate::logReceiveMessage(const QString &msg) const
-{
- if (engine)
- engine->logMessage(QLatin1String("QScriptDebuggerClient"), QmlEngine::LogReceive, msg);
-}
-
-} // Internal
-} // Debugger
diff --git a/src/plugins/debugger/qml/qscriptdebuggerclient.h b/src/plugins/debugger/qml/qscriptdebuggerclient.h
deleted file mode 100644
index a09a1839c2..0000000000
--- a/src/plugins/debugger/qml/qscriptdebuggerclient.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef QSCRIPTDEBUGGERCLIENT_H
-#define QSCRIPTDEBUGGERCLIENT_H
-
-#include "baseqmldebuggerclient.h"
-
-namespace Debugger {
-namespace Internal {
-
-class QScriptDebuggerClientPrivate;
-
-class QScriptDebuggerClient : public BaseQmlDebuggerClient
-{
- Q_OBJECT
-
-public:
- QScriptDebuggerClient(QmlDebug::QmlDebugConnection *client);
- ~QScriptDebuggerClient();
-
- void startSession();
- void endSession();
- void resetSession();
-
- void executeStep();
- void executeStepOut();
- void executeNext();
- void executeStepI();
-
- void executeRunToLine(const ContextData &data);
-
- void continueInferior();
- void interruptInferior();
-
- void activateFrame(int index);
-
- void insertBreakpoint(Breakpoint bp, int adjustedLine,
- int adjustedColumn = -1);
- void removeBreakpoint(Breakpoint bp);
- void changeBreakpoint(Breakpoint bp);
- void synchronizeBreakpoints();
-
- void assignValueInDebugger(const WatchData *data, const QString &expression,
- const QVariant &valueV);
-
- void updateWatchData(const WatchData &data);
- void executeDebuggerCommand(const QString &command);
-
- void synchronizeWatchers(const QStringList &watchers);
-
- void expandObject(const QByteArray &iname, quint64 objectId);
-
- void setEngine(QmlEngine *engine);
-
-protected:
- void messageReceived(const QByteArray &data);
-
-private:
- void sendPing();
- void insertLocalsAndWatches(QList<WatchData> &locals, QList<WatchData> &watches,
- int stackFrameIndex);
-
-private:
- QScriptDebuggerClientPrivate *d;
- friend class QScriptDebuggerClientPrivate;
-};
-
-} // Internal
-} // Debugger
-
-#endif // QSCRIPTDEBUGGERCLIENT_H
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 61ca2e1d53..6828971500 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -1268,6 +1268,11 @@ void WatchHandler::notifyUpdateFinished()
emit m_model->updateFinished();
}
+void WatchHandler::reexpandItems()
+{
+ m_model->reexpandItems();
+}
+
void WatchHandler::removeItemByIName(const QByteArray &iname)
{
WatchItem *item = m_model->findItem(iname);
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index aacbc6e0c2..890fd4d256 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -201,6 +201,8 @@ public:
void notifyUpdateStarted(const QList<QByteArray> &inames = {});
void notifyUpdateFinished();
+ void reexpandItems();
+
private:
WatchModel *m_model; // Owned.
};
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
index f62f05d0bf..3f798035cd 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
@@ -820,13 +820,15 @@ void JsonFieldPage::ComboBoxField::initializeData(MacroExpander *expander)
if (!tmpConditions.at(i)) {
tmpItems.removeAt(i);
tmpData.removeAt(i);
- if (i <= index)
+ if (i < index && index > 0)
--index;
}
}
+
+ if (index < 0 || index >= tmpData.count())
+ index = 0;
w->setItems(tmpItems, tmpData);
w->setInsertPolicy(QComboBox::NoInsert);
-
w->setCurrentIndex(index);
}
diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp
index 853a378e63..5d88012f3d 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.cpp
+++ b/src/plugins/qbsprojectmanager/qbsproject.cpp
@@ -797,8 +797,6 @@ void QbsProject::updateCppCodeModel()
}
}
- if (pinfo.projectParts().isEmpty())
- return;
pinfo.finish();
QtSupport::UiCodeModelManager::update(this, uiFiles);
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
index 62a1018881..4b466aa223 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
@@ -473,6 +473,7 @@ QString PropertyEditorQmlBackend::locateQmlFile(const NodeMetaInfo &info, const
static QDir resourcesDir(QStringLiteral(":/propertyEditorQmlSources"));
QDir importDir(info.importDirectoryPath() + QLatin1String(Constants::QML_DESIGNER_SUBFOLDER));
+ QDir importDirVersion(info.importDirectoryPath() + QStringLiteral(".") + QString::number(info.majorVersion()) + QLatin1String(Constants::QML_DESIGNER_SUBFOLDER));
const QString versionString = QStringLiteral("_") + QString::number(info.majorVersion())
+ QStringLiteral("_")
@@ -484,6 +485,14 @@ QString PropertyEditorQmlBackend::locateQmlFile(const NodeMetaInfo &info, const
//Check for qml files with versions first
const QString withoutDirWithVersion = relativePathWithVersion.split(QStringLiteral("/")).last();
+
+ const QString withoutDir = relativePath.split(QStringLiteral("/")).last();
+
+ if (importDirVersion.exists(withoutDir))
+ return importDirVersion.absoluteFilePath(withoutDir);
+
+
+
if (importDir.exists(relativePathWithVersion))
return importDir.absoluteFilePath(relativePathWithVersion);
if (importDir.exists(withoutDirWithVersion)) //Since we are in a subfolder of the import we do not require the directory
@@ -493,7 +502,7 @@ QString PropertyEditorQmlBackend::locateQmlFile(const NodeMetaInfo &info, const
if (resourcesDir.exists(relativePathWithVersion))
return resourcesDir.absoluteFilePath(relativePathWithVersion);
- const QString withoutDir = relativePath.split(QStringLiteral("/")).last();
+
if (importDir.exists(relativePath))
return importDir.absoluteFilePath(relativePath);
if (importDir.exists(withoutDir)) //Since we are in a subfolder of the import we do not require the directory
diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
index d6d95409b7..34f07c22ff 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
@@ -209,6 +209,15 @@ void SubComponentManager::parseDirectories()
foreach (const QString &path, importPaths()) {
QString fullUrl = path + QLatin1Char('/') + url;
dirInfo = QFileInfo(fullUrl);
+
+ if (dirInfo.exists() && dirInfo.isDir()) {
+ //### todo full qualified names QString nameSpace = import.uri();
+ parseDirectory(dirInfo.canonicalFilePath(), false);
+ }
+
+ QString fullUrlVersion = path + QLatin1Char('/') + url + QLatin1Char('.') + import.version().split(".").first();
+ dirInfo = QFileInfo(fullUrlVersion);
+
if (dirInfo.exists() && dirInfo.isDir()) {
//### todo full qualified names QString nameSpace = import.uri();
parseDirectory(dirInfo.canonicalFilePath(), false);
diff --git a/src/plugins/qtsupport/uicodemodelsupport.cpp b/src/plugins/qtsupport/uicodemodelsupport.cpp
index 0fb3f4154b..358784c1b9 100644
--- a/src/plugins/qtsupport/uicodemodelsupport.cpp
+++ b/src/plugins/qtsupport/uicodemodelsupport.cpp
@@ -47,8 +47,7 @@
#include <QFile>
#include <QFileInfo>
-
-enum { debug = 0 };
+#include <QLoggingCategory>
using namespace ProjectExplorer;
using namespace CPlusPlus;
@@ -79,20 +78,26 @@ UiCodeModelSupport::UiCodeModelSupport(CppTools::CppModelManager *modelmanager,
m_headerFileName(uiHeaderFile),
m_state(BARE)
{
- if (debug)
- qDebug()<<"ctor UiCodeModelSupport for"<<m_uiFileName<<uiHeaderFile;
+ QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
+ qCDebug(log) << "ctor UiCodeModelSupport for" << m_uiFileName << uiHeaderFile;
connect(&m_process, SIGNAL(finished(int)),
this, SLOT(finishProcess()));
+ init();
}
UiCodeModelSupport::~UiCodeModelSupport()
{
- if (debug)
- qDebug()<<"dtor ~UiCodeModelSupport for"<<m_uiFileName;
+ disconnect(&m_process, SIGNAL(finished(int)),
+ this, SLOT(finishProcess()));
+ m_process.kill();
+ CppTools::CppModelManager::instance()->emitAbstractEditorSupportRemoved(m_headerFileName);
+ QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
+ qCDebug(log) << "dtor ~UiCodeModelSupport for" << m_uiFileName;
}
void UiCodeModelSupport::init() const
{
+ QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
if (m_state != BARE)
return;
QDateTime sourceTime = QFileInfo(m_uiFileName).lastModified();
@@ -101,53 +106,43 @@ void UiCodeModelSupport::init() const
if (uiHeaderTime.isValid() && (uiHeaderTime > sourceTime)) {
QFile file(m_headerFileName);
if (file.open(QFile::ReadOnly | QFile::Text)) {
- if (debug)
- qDebug()<<"ui*h file is more recent then source file, using information from ui*h file"<<m_headerFileName;
+ qCDebug(log) << "init: ui*h file is more recent then source file, using information from ui*h file" << m_headerFileName;
QTextStream stream(&file);
m_contents = stream.readAll().toUtf8();
m_cacheTime = uiHeaderTime;
m_state = FINISHED;
+ notifyAboutUpdatedContents();
return;
}
}
- if (debug)
- qDebug()<<"ui*h file not found, or not recent enough, trying to create it on the fly";
+ qCDebug(log) << "ui*h file not found, or not recent enough, trying to create it on the fly";
QFile file(m_uiFileName);
if (file.open(QFile::ReadOnly | QFile::Text)) {
QTextStream stream(&file);
const QString contents = stream.readAll();
if (runUic(contents)) {
- if (debug)
- qDebug()<<"created on the fly";
+ qCDebug(log) << "created on the fly";
return;
} else {
// uic run was unsuccesfull
- if (debug)
- qDebug()<<"uic run wasn't succesfull";
+ qCDebug(log) << "uic run wasn't succesfull";
m_cacheTime = QDateTime ();
m_contents.clear();
m_state = FINISHED;
+ notifyAboutUpdatedContents();
return;
}
} else {
- if (debug)
- qDebug()<<"Could open "<<m_uiFileName<<"needed for the cpp model";
+ qCDebug(log) << "Could not open " << m_uiFileName << "needed for the cpp model";
m_contents.clear();
m_state = FINISHED;
+ notifyAboutUpdatedContents();
}
}
QByteArray UiCodeModelSupport::contents() const
{
- // Check the common case first
- if (m_state == FINISHED)
- return m_contents;
- if (m_state == BARE)
- init();
- if (m_state == RUNNING)
- finishProcess();
-
return m_contents;
}
@@ -166,16 +161,20 @@ void UiCodeModelSupport::setHeaderFileName(const QString &name)
if (m_headerFileName == name && m_cacheTime.isValid())
return;
- if (m_state == RUNNING)
- finishProcess();
+ if (m_state == RUNNING) {
+ m_state = ABORTING;
+ m_process.kill();
+ m_process.waitForFinished(3000);
+ }
- if (debug)
- qDebug() << "UiCodeModelSupport::setFileName"<<name;
+ QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
+ qCDebug(log) << "UiCodeModelSupport::setFileName" << name;
m_headerFileName = name;
m_contents.clear();
m_cacheTime = QDateTime();
m_state = BARE;
+ init();
}
bool UiCodeModelSupport::runUic(const QString &ui) const
@@ -183,10 +182,10 @@ bool UiCodeModelSupport::runUic(const QString &ui) const
const QString uic = uicCommand();
if (uic.isEmpty())
return false;
+ QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
m_process.setEnvironment(environment());
- if (debug)
- qDebug() << "UiCodeModelSupport::runUic " << uic << " on " << ui.size() << " bytes";
+ qCDebug(log) << " UiCodeModelSupport::runUic " << uic << " on " << ui.size() << " bytes";
m_process.start(uic, QStringList(), QIODevice::ReadWrite);
if (!m_process.waitForStarted())
return false;
@@ -198,8 +197,7 @@ bool UiCodeModelSupport::runUic(const QString &ui) const
return true;
error:
- if (debug)
- qDebug() << "failed" << m_process.readAllStandardError();
+ qCDebug(log) << "failed" << m_process.readAllStandardError();
m_process.kill();
m_state = FINISHED;
return false;
@@ -207,29 +205,26 @@ error:
void UiCodeModelSupport::updateFromEditor(const QString &formEditorContents)
{
- if (m_state == BARE)
- init();
- if (m_state == RUNNING)
- finishProcess();
- if (runUic(formEditorContents))
- if (finishProcess())
- updateDocument();
+ QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
+ qCDebug(log) << "updating from editor" << m_uiFileName;
+ if (m_state == RUNNING) {
+ m_state = ABORTING;
+ m_process.kill();
+ m_process.waitForFinished(3000);
+ }
+ runUic(formEditorContents);
}
void UiCodeModelSupport::updateFromBuild()
{
- if (debug)
- qDebug()<<"UiCodeModelSupport::updateFromBuild() for file"<<m_uiFileName;
- if (m_state == BARE)
- init();
- if (m_state == RUNNING)
- finishProcess();
+ QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
+ qCDebug(log) << "UiCodeModelSupport::updateFromBuild() for " << m_uiFileName;
+
// This is mostly a fall back for the cases when uic couldn't be run
// it pays special attention to the case where a ui_*h was newly created
QDateTime sourceTime = QFileInfo(m_uiFileName).lastModified();
if (m_cacheTime.isValid() && m_cacheTime >= sourceTime) {
- if (debug)
- qDebug()<<"Cache is still more recent then source";
+ qCDebug(log) << "Cache is still more recent then source";
return;
} else {
QFileInfo fi(m_headerFileName);
@@ -237,20 +232,19 @@ void UiCodeModelSupport::updateFromBuild()
if (uiHeaderTime.isValid() && (uiHeaderTime > sourceTime)) {
if (m_cacheTime >= uiHeaderTime)
return;
- if (debug)
- qDebug()<<"found ui*h updating from it";
+ qCDebug(log) << "found ui*h updating from it";
QFile file(m_headerFileName);
if (file.open(QFile::ReadOnly | QFile::Text)) {
QTextStream stream(&file);
m_contents = stream.readAll().toUtf8();
m_cacheTime = uiHeaderTime;
+ notifyAboutUpdatedContents();
updateDocument();
return;
}
}
- if (debug)
- qDebug()<<"ui*h not found or not more recent then source not changing anything";
+ qCDebug(log) << "ui*h not found or not more recent then source not changing anything";
}
}
@@ -279,34 +273,30 @@ QStringList UiCodeModelSupport::environment() const
}
}
-bool UiCodeModelSupport::finishProcess() const
+bool UiCodeModelSupport::finishProcess()
{
if (m_state != RUNNING)
return false;
+ QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
if (!m_process.waitForFinished(3000)
&& m_process.exitStatus() != QProcess::NormalExit
&& m_process.exitCode() != 0) {
- if (m_state != RUNNING) // waitForFinished can recurse into finishProcess
- return false;
- if (debug)
- qDebug() << "failed" << m_process.readAllStandardError();
+ qCDebug(log) << "finish process: failed" << m_process.readAllStandardError();
m_process.kill();
m_state = FINISHED;
return false;
}
- if (m_state != RUNNING) // waitForFinished can recurse into finishProcess
- return true;
-
// As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The
// conversion below is to normalize both the encoding, and the line terminators.
QString normalized = QString::fromLocal8Bit(m_process.readAllStandardOutput());
m_contents = normalized.toUtf8();
m_cacheTime = QDateTime::currentDateTime();
- if (debug)
- qDebug() << "ok" << m_contents.size() << "bytes.";
+ qCDebug(log) << "finish process: ok" << m_contents.size() << "bytes.";
m_state = FINISHED;
+ notifyAboutUpdatedContents();
+ updateDocument();
return true;
}
diff --git a/src/plugins/qtsupport/uicodemodelsupport.h b/src/plugins/qtsupport/uicodemodelsupport.h
index 333950e79c..91dbdb3361 100644
--- a/src/plugins/qtsupport/uicodemodelsupport.h
+++ b/src/plugins/qtsupport/uicodemodelsupport.h
@@ -73,11 +73,11 @@ private:
QStringList environment() const;
private slots:
- bool finishProcess() const;
+ bool finishProcess();
private:
ProjectExplorer::Project *m_project;
- enum State { BARE, RUNNING, FINISHED };
+ enum State { BARE, RUNNING, FINISHED, ABORTING };
void init() const;
bool runUic(const QString &ui) const;
diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp
index b4c8054d96..3263ad00b2 100644
--- a/tests/auto/debugger/tst_dumpers.cpp
+++ b/tests/auto/debugger/tst_dumpers.cpp
@@ -2962,6 +2962,14 @@ void tst_Dumpers::dumper_data()
+ Check4("url1.d.fragment", "\"\"", "@QString");
+ QTest::newRow("QUuid")
+ << Data("#include <QUuid>",
+ "QUuid uuid(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);\n"
+ "unused(&uuid);\n")
+ + CoreProfile()
+ + Check("uuid", "{00000001-0002-0003-0405-060708090a0b}", "@QUuid");
+
+
QByteArray expected1 = "\"AAA";
expected1.append(char('\t'));
expected1.append(char('\r'));
diff --git a/tests/manual/qml/testfiles/components/MyButton.qml b/tests/manual/qml/testfiles/components/MyButton.qml
deleted file mode 100644
index a2da722180..0000000000
--- a/tests/manual/qml/testfiles/components/MyButton.qml
+++ /dev/null
@@ -1,37 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-Rectangle {
- width: 64
- height: 48
- color: "Red"
-}
diff --git a/tests/manual/qml/testfiles/empty.qml b/tests/manual/qml/testfiles/empty.qml
deleted file mode 100644
index a59296037f..0000000000
--- a/tests/manual/qml/testfiles/empty.qml
+++ /dev/null
@@ -1,36 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-Rectangle {
- width: 640
- height: 480
-}
diff --git a/tests/manual/qml/testfiles/flipable.qml b/tests/manual/qml/testfiles/flipable.qml
deleted file mode 100644
index 2fc46c4567..0000000000
--- a/tests/manual/qml/testfiles/flipable.qml
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-Flipable {
- width: 640
- height: 480
- front: Text {
- text: "front"
- }
- back: Text {
- text: "back"
- }
-
-}
diff --git a/tests/manual/qml/testfiles/helloworld.qml b/tests/manual/qml/testfiles/helloworld.qml
deleted file mode 100644
index c0ab2b8bed..0000000000
--- a/tests/manual/qml/testfiles/helloworld.qml
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-Rectangle {
- width: 200
- height: 200
- Text {
- x: 66
- y: 93
- text: "Hello World"
- }
-}
diff --git a/tests/manual/qml/testfiles/helloworld_inverted.qml b/tests/manual/qml/testfiles/helloworld_inverted.qml
deleted file mode 100644
index 6bdd3e5b33..0000000000
--- a/tests/manual/qml/testfiles/helloworld_inverted.qml
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-Rectangle {
- width: 200
- height: 200
- color: "black"
- Text {
- x: 66
- y: 93
- text: "Hello World"
- color: "white"
- }
-}
diff --git a/tests/manual/qml/testfiles/images/qtcreator.ico b/tests/manual/qml/testfiles/images/qtcreator.ico
deleted file mode 100644
index 06209ee81e..0000000000
--- a/tests/manual/qml/testfiles/images/qtcreator.ico
+++ /dev/null
Binary files differ
diff --git a/tests/manual/qml/testfiles/images/qtcreator.jpg b/tests/manual/qml/testfiles/images/qtcreator.jpg
deleted file mode 100644
index 700af01ff1..0000000000
--- a/tests/manual/qml/testfiles/images/qtcreator.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/manual/qml/testfiles/images/qtcreator.png b/tests/manual/qml/testfiles/images/qtcreator.png
deleted file mode 100644
index b1d96b9c43..0000000000
--- a/tests/manual/qml/testfiles/images/qtcreator.png
+++ /dev/null
Binary files differ
diff --git a/tests/manual/qml/testfiles/listmodel.qml b/tests/manual/qml/testfiles/listmodel.qml
deleted file mode 100644
index 270bd0a6b2..0000000000
--- a/tests/manual/qml/testfiles/listmodel.qml
+++ /dev/null
@@ -1,40 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-ListModel {
- id: myModel
- ListElement {
- content: "foo"
- text: "bar"
- }
-
-}
diff --git a/tests/manual/qml/testfiles/listview.qml b/tests/manual/qml/testfiles/listview.qml
deleted file mode 100644
index 44f6cd170f..0000000000
--- a/tests/manual/qml/testfiles/listview.qml
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-Item {
- width: 200
- height: 100
-
- ListView {
- anchors.fill: parent;
- model: ListModel {
- ListElement {
- name: "BMW"
- speed: 200
- }
- ListElement {
- name: "Mercedes"
- speed: 180
- }
- ListElement {
- name: "Audi"
- speed: 190
- }
- ListElement {
- name: "VW"
- speed: 180
- }
- }
-
-
- delegate: Item {
- height: 40
- Row {
- spacing: 10
- Text {
- text: name;
- font.bold: true
- }
-
- Text { text: "speed: " + speed }
- }
-
-
- }
- }
-}
diff --git a/tests/manual/qml/testfiles/states.qml b/tests/manual/qml/testfiles/states.qml
deleted file mode 100644
index 1d614cea34..0000000000
--- a/tests/manual/qml/testfiles/states.qml
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-Rectangle {
- id: rect
- width: 200
- height: 200
- Text {
- id: text
- x: 66
- y: 93
- text: "Base State"
- }
- states: [
- State {
- name: "State1"
- PropertyChanges {
- target: rect
- color: "blue"
- }
- PropertyChanges {
- target: text
- text: "State1"
- }
- },
- State {
- name: "State2"
- PropertyChanges {
- target: rect
- color: "gray"
- }
- PropertyChanges {
- target: text
- text: "State2"
- }
- }
- ]
-
- Image {
- id: image1
- x: 41
- y: 46
- source: "images/qtcreator.png"
- }
-}
diff --git a/tests/manual/qml/testfiles/subcomponent.qml b/tests/manual/qml/testfiles/subcomponent.qml
deleted file mode 100644
index 48d4dd9c12..0000000000
--- a/tests/manual/qml/testfiles/subcomponent.qml
+++ /dev/null
@@ -1,47 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-
-Rectangle {
- width: 640
- height: 480
- Component {
- id: redSquare
- Rectangle {
- color: "red"
- width: 100
- height: 100
- }
- }
-
- Loader { sourceComponent: redSquare;}
- Loader { sourceComponent: redSquare; x: 20 }
-}
diff --git a/tests/manual/qml/testfiles/testfiles.qmlproject b/tests/manual/qml/testfiles/testfiles.qmlproject
deleted file mode 100644
index 86a56698e2..0000000000
--- a/tests/manual/qml/testfiles/testfiles.qmlproject
+++ /dev/null
@@ -1,16 +0,0 @@
-// File generated by QtCreator
-
-import QmlProject 1.0
-
-Project {
- // Scan current directory for .qml, .js, and image files
- QmlFiles {
- directory: "."
- }
- JavaScriptFiles {
- directory: "."
- }
- ImageFiles {
- directory: "."
- }
-}
diff --git a/tests/manual/qml/testfiles/usingbutton.qml b/tests/manual/qml/testfiles/usingbutton.qml
deleted file mode 100644
index 4d7fc38466..0000000000
--- a/tests/manual/qml/testfiles/usingbutton.qml
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-import "components" as X
-
-Rectangle {
- width: 640
- height: 480
-
- X.MyButton {
- }
-
-}
diff --git a/tests/manual/qml/testfiles/webview.qml b/tests/manual/qml/testfiles/webview.qml
deleted file mode 100644
index 567b48f568..0000000000
--- a/tests/manual/qml/testfiles/webview.qml
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-import QtQuick 1.1
-import QtWebKit 1.0
-
-// Test loading of import libraries
-WebView {
- width: 640
- height: 480
-
- html:"\
- <body bgcolor=white>\
- Hello World\
- </body>"
-}
diff --git a/tests/system/objects.map b/tests/system/objects.map
index f6ef8dbb4f..e96b9ea1c1 100644
--- a/tests/system/objects.map
+++ b/tests/system/objects.map
@@ -105,7 +105,7 @@
:Hits_QCLuceneResultWidget {aboveWidget=':Hits_QLabel' type='QCLuceneResultWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Hits_QLabel {text~='\\\\d+ - \\\\d+ of \\\\d+ Hits' type='QLabel' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:JavaScript.QmlProfilerEventsTable_QmlProfiler::Internal::QV8ProfilerEventsMainView {container=':*Qt Creator.JavaScript_QDockWidget' name='QmlProfilerEventsTable' type='QmlProfiler::Internal::QV8ProfilerEventsMainView' visible='1'}
-:Kits_QtVersion_QComboBox {container=':qt_tabwidget_stackedwidget_QWidget' occurrence='5' type='QComboBox' unnamed='1' visible='1'}
+:Kits_QtVersion_QComboBox {container=':qt_tabwidget_stackedwidget_QWidget' leftWidget=':QtVersionLabel_KitPage' type='QComboBox' unnamed='1' visible='1'}
:Locals and Expressions_Debugger::Internal::WatchTreeView {container=':DebugModeWidget.Locals and Expressions_QDockWidget' name='WatchWindow' type='Debugger::Internal::WatchTreeView' visible='1' windowTitle='Locals and Expressions'}
:Minimal required Qt version:_QLabel {text='Minimal required Qt version:' type='QLabel' unnamed='1' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'}
:New Text File.Add to project:_QLabel {name='projectLabel' text='Add to project:' type='QLabel' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'}
@@ -182,6 +182,7 @@
:QtSupport__Internal__QtVersionManager.errorLabel.QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='errorLabel' type='QLabel' visible='1'}
:QtSupport__Internal__QtVersionManager.qmake_QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='qmakePath' type='QLabel' visible='1'}
:QtSupport__Internal__QtVersionManager.qtdirList_QTreeWidget {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='qtdirList' type='QTreeWidget' visible='1'}
+:QtVersionLabel_KitPage {container=':qt_tabwidget_stackedwidget_QWidget' text='Qt version:' type='QLabel' unnamed='1' visible='1'}
:Restart required.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Restart required_QMessageBox'}
:Restart required_QMessageBox {text='The language change will take effect after a restart of Qt Creator.' type='QMessageBox' unnamed='1' visible='1'}
:Revert to Saved.Proceed_QPushButton {text='Proceed' type='QPushButton' unnamed='1' visible='1' window=':Revert to Saved_QMessageBox'}
diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py
index ebd403254e..7df1631dd7 100644
--- a/tests/system/shared/project.py
+++ b/tests/system/shared/project.py
@@ -270,26 +270,39 @@ def createProject_Qt_Console(path, projectName, checks = True):
def createNewQtQuickApplication(workingDir, projectName = None,
targets=Targets.desktopTargetClasses(), minimumQtVersion="5.3",
- fromWelcome=False):
- available = __createProjectOrFileSelectType__(" Application", "Qt Quick Application", fromWelcome)
+ withControls = False, fromWelcome=False):
+ if withControls:
+ template = "Qt Quick Controls Application"
+ else:
+ template = "Qt Quick Application"
+ available = __createProjectOrFileSelectType__(" Application", template, fromWelcome)
projectName = __createProjectSetNameAndPath__(workingDir, projectName)
requiredQt = __createProjectHandleQtQuickSelection__(minimumQtVersion)
__modifyAvailableTargets__(available, requiredQt)
checkedTargets = __chooseTargets__(targets, available)
snooze(1)
- clickButton(waitForObject(":Next_QPushButton"))
- __createProjectHandleLastPage__()
+ if len(checkedTargets):
+ clickButton(waitForObject(":Next_QPushButton"))
+ __createProjectHandleLastPage__()
+ progressBarWait(10000)
+ else:
+ clickButton(waitForObject("{type='QPushButton' text='Cancel' visible='1'}"))
- progressBarWait(10000)
return checkedTargets, projectName
-def createNewQtQuickUI(workingDir, qtQuickVersion="1.1"):
- __createProjectOrFileSelectType__(" Application", "Qt Quick UI")
+def createNewQtQuickUI(workingDir, qtVersion = "5.3", withControls = False):
+ if withControls:
+ template = 'Qt Quick Controls UI'
+ else:
+ template = 'Qt Quick UI'
+ __createProjectOrFileSelectType__(" Other Project", template)
if workingDir == None:
workingDir = tempDir()
projectName = __createProjectSetNameAndPath__(workingDir)
- __createProjectHandleQtQuickSelection__(qtQuickVersion)
+ __createProjectHandleQtQuickSelection__(qtVersion)
__createProjectHandleLastPage__()
+ progressBarWait(10000)
+
return projectName
def createNewQmlExtension(workingDir, targets=Targets.DESKTOP_474_GCC, qtQuickVersion=1):
diff --git a/tests/system/shared/project_explorer.py b/tests/system/shared/project_explorer.py
index 0a7bd0e36e..c68633af22 100644
--- a/tests/system/shared/project_explorer.py
+++ b/tests/system/shared/project_explorer.py
@@ -217,19 +217,15 @@ def __selectTreeItemOnBuildAndRun__(treeViewOrWidget, itemText, isRegex=False):
test.compare(manual.data().toString(), "Manual", "Verifying label for section")
if isRegex:
pattern = re.compile(itemText)
- found = False
for section in [autoDetected, manual]:
for dumpedItem in dumpItems(model, section):
if (isRegex and pattern.match(dumpedItem)
or itemText == dumpedItem):
- found = True
item = ".".join([str(section.data().toString()),
dumpedItem.replace(".", "\\.").replace("_", "\\_")])
clickItem(treeViewOrWidget, item, 5, 5, 0, Qt.LeftButton)
- break
- if found:
- break
- return found
+ return True
+ return False
def __getTargetFromToolTip__(toolTip):
if toolTip == None or not isinstance(toolTip, (str, unicode)):
diff --git a/tests/system/suite_debugger/tst_qml_js_console/test.py b/tests/system/suite_debugger/tst_qml_js_console/test.py
index c149eeb4a2..f6729f4c5a 100644
--- a/tests/system/suite_debugger/tst_qml_js_console/test.py
+++ b/tests/system/suite_debugger/tst_qml_js_console/test.py
@@ -123,7 +123,7 @@ def main():
return
qmlProjFile = os.path.join(qmlProjDir, projName)
# start Creator by passing a .qmlproject file
- startApplication('qtcreator -load QmlProjectManager' + SettingsPath + ' "%s"' % qmlProjFile)
+ startApplication('qtcreator' + SettingsPath + ' "%s"' % qmlProjFile)
if not startedWithoutPluginError():
return
@@ -142,10 +142,6 @@ def main():
rootIndex = getQModelIndexStr("text='Rectangle'",
":Locals and Expressions_Debugger::Internal::WatchTreeView")
# make sure the items inside the root item are visible
- if JIRA.isBugStillOpen(14210):
- doubleClick(waitForObject(rootIndex))
- else:
- test.warning("QTCREATORBUG-14210 is not open anymore. Can the workaround be removed?")
doubleClick(waitForObject(rootIndex))
if not object.exists(":DebugModeWidget_QmlJSTools::Internal::QmlConsoleView"):
invokeMenuItem("Window", "Output Panes", "QML/JS Console")
@@ -156,14 +152,14 @@ def main():
("color ='silver'", "silver", "color", u"#\u200bc0c0c0"),
("width=66", "66", "width"), ("anchors.centerIn", "<unnamed object>"),
("opacity", "1"), ("opacity = .2", u"0.\u200b2", "opacity")]
- # check green inner Rectangle
- runChecks("text='Rectangle'", rootIndex, checks)
+ # check red inner Rectangle
+ runChecks("text='Rectangle' occurrence='2'", rootIndex, checks)
checks = [("color", u"#\u200bff0000"), ("width", "100"), ("height", "100"),
("radius = Math.min(width, height) / 2", "50", "radius"),
("parent.objectName= 'mainRect'", "mainRect")]
- # check red inner Rectangle
- runChecks("text='Rectangle' occurrence='2'", rootIndex, checks)
+ # check green inner Rectangle
+ runChecks("text='Rectangle'", rootIndex, checks)
checks = [("color", u"#\u200b000000"), ("font.pointSize=14", "14", "font.pointSize"),
("font.bold", "false"), ("font.weight=Font.Bold", "75", "font.bold", "true"),
diff --git a/tests/system/suite_debugger/tst_qml_locals/test.py b/tests/system/suite_debugger/tst_qml_locals/test.py
index a9010d00a3..65291273ce 100644
--- a/tests/system/suite_debugger/tst_qml_locals/test.py
+++ b/tests/system/suite_debugger/tst_qml_locals/test.py
@@ -45,7 +45,7 @@ def main():
return
qmlProjFile = os.path.join(qmlProjDir, projName)
# start Creator by passing a .qmlproject file
- startApplication('qtcreator -load QmlProjectManager' + SettingsPath + ' "%s"' % qmlProjFile)
+ startApplication('qtcreator' + SettingsPath + ' "%s"' % qmlProjFile)
if not startedWithoutPluginError():
return
waitFor('object.exists(":Qt Creator_Utils::NavigationTreeView")', 10000)
@@ -91,8 +91,8 @@ def main():
checkForEmptyRows(items)
check = [[None, 0, {"Properties":1, "Rectangle":2, "Text":1}, {"width":"360", "height":"360"}],
["Text", 1, {"Properties":1}, {"text":"Check"}],
- ["Rectangle", 1, {"Properties":1}, {"width":"50", "height":"50", "color":"#008000"}],
- ["Rectangle", 2, {"Properties":1}, {"width":"100", "height":"100", "color":"#ff0000"}]
+ ["Rectangle", 2, {"Properties":1}, {"width":"50", "height":"50", "color":"#008000"}],
+ ["Rectangle", 1, {"Properties":1}, {"width":"100", "height":"100", "color":"#ff0000"}]
]
for current in check:
if current[0]:
@@ -108,23 +108,19 @@ def main():
def __unfoldTree__():
rootIndex = getQModelIndexStr("text='Rectangle'",
':Locals and Expressions_Debugger::Internal::WatchTreeView')
- if JIRA.isBugStillOpen(14210):
- doubleClick(waitForObject(rootIndex))
- else:
- test.warning("QTCREATORBUG-14210 is not open anymore. Can the workaround be removed?")
unfoldQModelIndexIncludingProperties(rootIndex)
- if JIRA.isBugStillOpen(14210):
- for item in ["text='Rectangle' occurrence='2'", "text='Rectangle' occurrence='2'", "text='Text'"]:
- # both Rectangles will be clicked because they change their order
- doubleClick(waitForObject(getQModelIndexStr(item, rootIndex)))
- snooze(1)
- subItems = ["text='Rectangle' occurrence='2'", "text='Rectangle'", "text='Text'"]
+ subItems = ["text='Rectangle'", "text='Rectangle' occurrence='2'", "text='Text'"]
for item in subItems:
unfoldQModelIndexIncludingProperties(getQModelIndexStr(item, rootIndex))
def unfoldQModelIndexIncludingProperties(indexStr):
+ tv = waitForObject(':Locals and Expressions_Debugger::Internal::WatchTreeView')
+ # HACK to avoid failing clicks
+ tv.scrollToBottom()
doubleClick(waitForObject(indexStr))
propIndex = getQModelIndexStr("text='Properties'", indexStr)
+ # HACK to avoid failing clicks
+ tv.scrollToBottom()
doubleClick(waitForObject(propIndex))
def fetchItems(index, valIndex, treeView):
diff --git a/tests/system/suite_qtquick/tst_qtquick_creation/test.py b/tests/system/suite_qtquick/tst_qtquick_creation/test.py
index 3a3562c22f..e3012d0468 100644
--- a/tests/system/suite_qtquick/tst_qtquick_creation/test.py
+++ b/tests/system/suite_qtquick/tst_qtquick_creation/test.py
@@ -34,16 +34,31 @@ def main():
startApplication("qtcreator" + SettingsPath)
if not startedWithoutPluginError():
return
- for targ, qVer in [[Targets.DESKTOP_480_DEFAULT, "1.1"], [Targets.DESKTOP_521_DEFAULT, "2.1"],
- [Targets.DESKTOP_521_DEFAULT, "2.2"], [Targets.DESKTOP_531_DEFAULT, "2.3"],
- [Targets.DESKTOP_521_DEFAULT, "Controls 1.0"], [Targets.DESKTOP_521_DEFAULT, "Controls 1.1"],
- [Targets.DESKTOP_531_DEFAULT, "Controls 1.2"]]:
+
+ available = [("5.3", False), ("5.3", True)]
+ if platform.system() != 'Darwin':
+ available.extend([("5.4", False), ("5.4", True)])
+
+ for qtVersion, controls in available:
+ if qtVersion == "5.3":
+ targ = Targets.DESKTOP_531_DEFAULT
+ quick = "2.3"
+ else:
+ targ = Targets.DESKTOP_541_GCC
+ quick = "2.4"
# using a temporary directory won't mess up a potentially existing
workingDir = tempDir()
checkedTargets, projectName = createNewQtQuickApplication(workingDir, targets=targ,
- qtQuickVersion=qVer)
- test.log("Building project Qt Quick %s Application (%s)"
- % (qVer, Targets.getStringForTarget(targ)))
+ minimumQtVersion=qtVersion,
+ withControls = controls)
+ if len(checkedTargets) == 0:
+ test.fatal("Could not check wanted target")
+ continue
+ additionalText = ''
+ if controls:
+ additionalText = ' Controls '
+ test.log("Building project Qt Quick%sApplication (%s)"
+ % (additionalText, Targets.getStringForTarget(targ)))
result = modifyRunSettingsForHookInto(projectName, len(checkedTargets), 11223)
invokeMenuItem("Build", "Build All")
waitForCompile()
@@ -57,10 +72,8 @@ def main():
allowAppThroughWinFW(workingDir, projectName)
if result:
function = "subprocessFunctionQuick2"
- if qVer[0] == "1":
- function = "subprocessFunctionQuick1"
result = runAndCloseApp(True, projectName, 11223, function,
- SubprocessType.QT_QUICK_APPLICATION, quickVersion=qVer)
+ SubprocessType.QT_QUICK_APPLICATION, quickVersion=quick)
else:
result = runAndCloseApp(sType=SubprocessType.QT_QUICK_APPLICATION)
removeExecutableAsAttachableAUT(projectName, 11223)
@@ -70,7 +83,9 @@ def main():
if result == None:
checkCompile()
else:
- logApplicationOutput()
+ appOutput = logApplicationOutput()
+ test.verify(not ("main.qml" in appOutput or "MainForm.ui.qml" in appOutput),
+ "Does the Application Output indicate QML errors?")
invokeMenuItem("File", "Close All Projects and Editors")
invokeMenuItem("File", "Exit")
@@ -82,8 +97,5 @@ def subprocessFunctionGenericQuick(quickVersion):
test.log("Clicking 'Hello World' Text to close QtQuick%dApplicationViewer" % quickVersion)
mouseClick(helloWorldText, 5, 5, 0, Qt.LeftButton)
-def subprocessFunctionQuick1():
- subprocessFunctionGenericQuick(1)
-
def subprocessFunctionQuick2():
subprocessFunctionGenericQuick(2)
diff --git a/tests/system/suite_qtquick/tst_qtquick_creation3/test.py b/tests/system/suite_qtquick/tst_qtquick_creation3/test.py
index aa3347118d..345d6cae73 100644
--- a/tests/system/suite_qtquick/tst_qtquick_creation3/test.py
+++ b/tests/system/suite_qtquick/tst_qtquick_creation3/test.py
@@ -31,30 +31,42 @@
source("../../shared/qtcreator.py")
def main():
- startApplication("qtcreator -load QmlProjectManager" + SettingsPath)
+ startApplication("qtcreator" + SettingsPath)
if not startedWithoutPluginError():
return
- for quickVersion in ["1.1", "2.1", "2.2", "2.3", "Controls 1.0", "Controls 1.1", "Controls 1.2"]:
+ available = [("5.3", False), ("5.3", True)]
+ if platform.system() != 'Darwin':
+ available.extend([("5.4", False), ("5.4", True)])
+
+ for qtVersion, controls in available:
# using a temporary directory won't mess up a potentially existing
workingDir = tempDir()
- projectName = createNewQtQuickUI(workingDir, quickVersion)
+ projectName = createNewQtQuickUI(workingDir, qtVersion, controls)
switchViewTo(ViewConstants.PROJECTS)
clickButton(waitForObject(":*Qt Creator.Add Kit_QPushButton"))
- menuItem = Targets.getStringForTarget(Targets.DESKTOP_531_DEFAULT)
+ if qtVersion == "5.3":
+ menuItem = Targets.getStringForTarget(Targets.DESKTOP_531_DEFAULT)
+ quick = "2.3"
+ else:
+ menuItem = Targets.getStringForTarget(Targets.DESKTOP_541_GCC)
+ quick = "2.4"
if platform.system() == 'Darwin':
waitFor("macHackActivateContextMenuItem(menuItem)", 5000)
else:
activateItem(waitForObjectItem("{type='QMenu' unnamed='1' visible='1' "
"window=':Qt Creator_Core::Internal::MainWindow'}", menuItem))
- test.log("Running project Qt Quick %s UI" % quickVersion)
- qmlViewer = modifyRunSettingsForHookIntoQtQuickUI(2, 1, workingDir, projectName, 11223, quickVersion)
+ additionalText = ''
+ if controls:
+ additionalText = ' Controls '
+ test.log("Running project Qt Quick%sUI (%s)" % (additionalText, menuItem))
+ qmlViewer = modifyRunSettingsForHookIntoQtQuickUI(2, 1, workingDir, projectName, 11223, quick)
if qmlViewer!=None:
qmlViewerPath = os.path.dirname(qmlViewer)
qmlViewer = os.path.basename(qmlViewer)
result = addExecutableAsAttachableAUT(qmlViewer, 11223)
allowAppThroughWinFW(qmlViewerPath, qmlViewer, None)
if result:
- result = runAndCloseApp(True, qmlViewer, 11223, sType=SubprocessType.QT_QUICK_UI, quickVersion=quickVersion)
+ result = runAndCloseApp(True, qmlViewer, 11223, sType=SubprocessType.QT_QUICK_UI, quickVersion=quick)
else:
result = runAndCloseApp(sType=SubprocessType.QT_QUICK_UI)
removeExecutableAsAttachableAUT(qmlViewer, 11223)
@@ -64,6 +76,8 @@ def main():
if result == None:
checkCompile()
else:
- logApplicationOutput()
+ appOutput = logApplicationOutput()
+ test.verify(not ("untitled.qml" in appOutput or "MainForm.ui.qml" in appOutput),
+ "Does the Application Output indicate QML errors?")
invokeMenuItem("File", "Close All Projects and Editors")
invokeMenuItem("File", "Exit")