Merge remote-tracking branch 'origin/4.2'
Change-Id: I3a54f679238e6eb4f053608286fc39eae3041561
30
README.md
@@ -19,6 +19,9 @@ Prerequisites:
|
||||
* ActiveState Active Perl
|
||||
* MinGW with g++ 4.8 or Visual Studio 2015 or later
|
||||
* jom
|
||||
|
||||
The optional Clang code model requires LLVM. A manual build of it requires in addition:
|
||||
* cmake
|
||||
* On Mac OS X: latest Xcode
|
||||
* On Linux: g++ 4.8 or later
|
||||
* LLVM 3.8.0 or later (optional, needed for the Clang Code Model)
|
||||
@@ -118,9 +121,32 @@ For detailed information on the supported compilers, see
|
||||
command...` error. If a `sh.exe` is found, the compile process will fail.
|
||||
You have to remove it from the path.
|
||||
|
||||
10. To enable the Clang-based code model: Install Clang (>= version 3.8.0)
|
||||
and set the environment variable LLVM_INSTALL_DIR to point to the
|
||||
10. As of Qt Creator 4.2, a complete build of LLVM and Clang is required
|
||||
to enable the Clang-based code model (recommmended: 3.9). For 32bit,
|
||||
a pre-built package can be downloaded from:
|
||||
https://download.qt.io/development_releases/prebuilt/libclang/.
|
||||
The environment variable LLVM_INSTALL_DIR needs to be set to point to the
|
||||
installation location.
|
||||
It is also possible to build Clang manually, roughly following the
|
||||
instructions at http://llvm.org/docs/GettingStarted.html#git-mirror .
|
||||
* Clone LLVM
|
||||
git clone http://llvm.org/git/llvm.git
|
||||
* Switch to a suitable branch, for example, release_39
|
||||
cd llvm
|
||||
git checkout -b release_39
|
||||
* Clone Clang under llvm\tools
|
||||
cd tools
|
||||
git clone http://llvm.org/git/clang.git
|
||||
* Switch Clang to a suitable branch
|
||||
cd clang
|
||||
git checkout -b release_39
|
||||
* Create a shadow build directory and build
|
||||
cd ..\..\..
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=<installation location> -DLLVM_ENABLE_RTTI=ON ..\llvm
|
||||
jom install
|
||||
|
||||
|
||||
11. You are now ready to configure and build Qt and Qt Creator.
|
||||
Please see <https://wiki.qt.io/Building_Qt_5_from_Git> for
|
||||
|
||||
72
dist/changes-4.1.1.md
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
Qt Creator version 4.1.1 contains bug fixes.
|
||||
|
||||
The most important changes are listed in this document. For a complete
|
||||
list of changes, see the Git log for the Qt Creator sources that
|
||||
you can check out from the public Git repository. For example:
|
||||
|
||||
git clone git://code.qt.io/qt-creator/qt-creator.git
|
||||
git log --cherry-pick --pretty=oneline v4.1.0..v4.1.1
|
||||
|
||||
General
|
||||
|
||||
* Fixed issues with output pane height
|
||||
(QTCREATORBUG-15986, QTCREATORBUG-16829)
|
||||
|
||||
Editing
|
||||
|
||||
* Fixed performance of cleaning whitespace (QTCREATORBUG-16420)
|
||||
* Fixed selection color in help viewer for dark theme (QTCREATORBUG-16375)
|
||||
|
||||
Help
|
||||
|
||||
* Fixed that no results could be shown in Locator (QTCREATORBUG-16753)
|
||||
|
||||
QMake Projects
|
||||
|
||||
* Fixed issue with make steps in deploy configurations (QTCREATORBUG-16795)
|
||||
|
||||
Qbs Projects
|
||||
|
||||
* Fixed handling of generated files (QTCREATORBUG-16976)
|
||||
|
||||
QML Support
|
||||
|
||||
* Fixed handling of circular dependencies (QTCREATORBUG-16585)
|
||||
|
||||
Debugging
|
||||
|
||||
* Fixed scrolling in memory editor (QTCREATORBUG-16751)
|
||||
* Fixed expansion of items in tool tip (QTCREATORBUG-16947)
|
||||
* GDB
|
||||
* Fixed handling of built-in pretty printers from new versions of GDB
|
||||
(QTCREATORBUG-16758)
|
||||
* Fixed that remote working directory was used for local process
|
||||
(QTCREATORBUG-16211)
|
||||
* CDB
|
||||
* Fixed display order of vectors in vectors (QTCREATORBUG-16813)
|
||||
* Fixed display of QList contents (QTCREATORBUG-16750)
|
||||
|
||||
QML Profiler
|
||||
|
||||
* Separated compile events from other QML/JS events in statistics and
|
||||
flamegraph, since compilation can happen asynchronously
|
||||
|
||||
Beautifier
|
||||
|
||||
* Fixed that beautifier was not enabled for Objective-C/C++ files
|
||||
(QTCREATORBUG-16806)
|
||||
|
||||
Platform Specific
|
||||
|
||||
macOS
|
||||
|
||||
* Fixed issue with detecting LLDB through `xcrun`
|
||||
|
||||
Android
|
||||
|
||||
* Added API level 24 for Android 7
|
||||
* Fixed debugging on Android 6+ with NDK r11+ (QTCREATORBUG-16721)
|
||||
|
||||
iOS
|
||||
|
||||
* Fixed QML debugging on device (QTCREATORBUG-15812)
|
||||
@@ -38,12 +38,14 @@
|
||||
\title Specifying Build Settings
|
||||
|
||||
Different build configurations allow you to quickly switch between
|
||||
different build settings. By default, \QC creates \b debug
|
||||
and \b release build configurations. A debug build contains additional
|
||||
different build settings. By default, \QC creates \e debug, \e release, and
|
||||
\e profile build configurations. A debug build contains additional
|
||||
debug symbols that you need for debugging the application but that you
|
||||
can leave out from the release version. Generally, you use the debug
|
||||
configuration for testing and the release configuration for creating
|
||||
the final installation file.
|
||||
the final installation file. A profile configuration is an optimized release
|
||||
build that is delivered with separate debug information. It is best suited
|
||||
for analyzing applications.
|
||||
|
||||
You specify build settings in the \uicontrol Projects mode.
|
||||
To add a new build configuration, click \uicontrol Add and select the type of
|
||||
|
||||
111
scripts/createSourcePackages.py
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (C) 2016 The Qt Company Ltd.
|
||||
# Contact: https://www.qt.io/licensing/
|
||||
#
|
||||
# This file is part of Qt Creator.
|
||||
#
|
||||
# Commercial License Usage
|
||||
# Licensees holding valid commercial Qt licenses may use this file in
|
||||
# accordance with the commercial license agreement provided with the
|
||||
# Software or, alternatively, in accordance with the terms contained in
|
||||
# a written agreement between you and The Qt Company. For licensing terms
|
||||
# and conditions see https://www.qt.io/terms-conditions. For further
|
||||
# information use the contact form at https://www.qt.io/contact-us.
|
||||
#
|
||||
# GNU General Public License Usage
|
||||
# Alternatively, this file may be used under the terms of the GNU
|
||||
# General Public License version 3 as published by the Free Software
|
||||
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
# included in the packaging of this file. Please review the following
|
||||
# information to ensure the GNU General Public License requirements will
|
||||
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
def archive(repository, target_file, prefix='', crlf=False):
|
||||
crlf_args = (['-c', 'core.autocrlf=true', '-c', 'core.eol=crlf'] if crlf
|
||||
else [])
|
||||
subprocess.check_call(['git'] + crlf_args +
|
||||
['archive', '--format=tar', '--prefix=' + prefix,
|
||||
'-o', target_file, 'HEAD'],
|
||||
cwd=repository)
|
||||
|
||||
def extract_combined(archive_list, target_dir):
|
||||
if not os.path.exists(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
for a in archive_list:
|
||||
subprocess.check_call(['tar', 'xf', a], cwd=target_dir)
|
||||
|
||||
def createTarGz(source_dir, target_file):
|
||||
(cwd, path) = os.path.split(source_dir)
|
||||
subprocess.check_call(['tar', 'czf', target_file, path], cwd=cwd)
|
||||
|
||||
def createTarXz(source_dir, target_file):
|
||||
(cwd, path) = os.path.split(source_dir)
|
||||
subprocess.check_call(['tar', 'cJf', target_file, path], cwd=cwd)
|
||||
|
||||
def createZip(source_dir, target_file):
|
||||
(cwd, path) = os.path.split(source_dir)
|
||||
subprocess.check_call(['zip', '-9qr', target_file, path], cwd=cwd)
|
||||
|
||||
def package_repos(repos, combined_prefix, target_file_base):
|
||||
workdir = tempfile.mkdtemp(suffix="-createQtcSource")
|
||||
def crlf_postfix(crlf):
|
||||
return '_win' if crlf else ''
|
||||
def tar_name(name, crlf):
|
||||
sanitized_name = name.replace('/', '_').replace('\\', '_')
|
||||
return os.path.join(workdir, sanitized_name + crlf_postfix(crlf) + '.tar')
|
||||
def archive_path(crlf=False):
|
||||
return os.path.join(workdir, 'src' + crlf_postfix(crlf), combined_prefix)
|
||||
print('Working in "' + workdir + '"')
|
||||
print('Pre-packaging archives...')
|
||||
for (name, repo, prefix) in repos:
|
||||
print(' ' + name + '...')
|
||||
for crlf in [False, True]:
|
||||
archive(repo, tar_name(name, crlf), prefix, crlf=crlf)
|
||||
print('Preparing for packaging...')
|
||||
for crlf in [False, True]:
|
||||
archive_list = [tar_name(name, crlf) for (name, _, _) in repos]
|
||||
extract_combined(archive_list, archive_path(crlf))
|
||||
print('Creating .tar.gz...')
|
||||
createTarGz(archive_path(crlf=False), target_file_base + '.tar.gz')
|
||||
print('Creating .tar.xz...')
|
||||
createTarGz(archive_path(crlf=False), target_file_base + '.tar.xz')
|
||||
print('Creating .zip with CRLF...')
|
||||
createZip(archive_path(crlf=True), target_file_base + '.zip')
|
||||
print('Removing temporary directory...')
|
||||
shutil.rmtree(workdir)
|
||||
|
||||
def parse_arguments():
|
||||
script_path = os.path.dirname(os.path.realpath(__file__))
|
||||
qtcreator_repo = os.path.join(script_path, '..')
|
||||
parser = argparse.ArgumentParser(description="Create Qt Creator source packages")
|
||||
parser.add_argument('-p', default=qtcreator_repo, dest='repo', help='path to repository')
|
||||
parser.add_argument('-n', default='', dest='name', help='name of plugin')
|
||||
parser.add_argument('-s', action='append', default=[], dest='modules', help='submodule to add')
|
||||
parser.add_argument('version', help='full version including tag, e.g. 4.2.0-beta1')
|
||||
parser.add_argument('edition', help='(opensource | enterprise)')
|
||||
return parser.parse_args()
|
||||
|
||||
def main():
|
||||
args = parse_arguments()
|
||||
base_repo_name = args.name if args.name else "qtcreator"
|
||||
if not args.name and not args.modules: # default Qt Creator repository
|
||||
args.modules = [os.path.join('src', 'shared', 'qbs')]
|
||||
repos = [(base_repo_name, args.repo, '')]
|
||||
for module in args.modules:
|
||||
repos += [(module, os.path.join(args.repo, module), module + os.sep)]
|
||||
name_part = '-' + args.name if args.name else ''
|
||||
prefix = 'qt-creator-' + args.edition + name_part + '-src-' + args.version
|
||||
package_repos(repos, prefix, os.path.join(os.getcwd(), prefix))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,55 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
## Command line parameters
|
||||
if [[ $# != 2 ]]; then
|
||||
cat <<USAGE
|
||||
usage:
|
||||
$0 <version> <edition>
|
||||
|
||||
Creates tar and zip source package from HEAD of the main repository and submodules.
|
||||
Files and directories are named after qt-creator-<edition>-src-<version>.
|
||||
example:
|
||||
$0 2.2.0-beta opensource
|
||||
USAGE
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION=$1
|
||||
EDITION=$2
|
||||
PREFIX=qt-creator-${EDITION}-src-${VERSION}
|
||||
cd `dirname $0`/..
|
||||
RESULTDIR=`pwd`
|
||||
TEMPSOURCES=`mktemp -d -t qtcCreatorSourcePackage.XXXXXX`
|
||||
echo "Temporary directory: ${TEMPSOURCES}"
|
||||
echo "Creating tar archive..."
|
||||
|
||||
echo " Creating tar sources of repositories..."
|
||||
git archive --format=tar --prefix=${PREFIX}/ HEAD > ${TEMPSOURCES}/__qtcreator_main.tar || exit 1
|
||||
echo " qbs..."
|
||||
cd src/shared/qbs || exit 1
|
||||
git archive --format=tar --prefix=${PREFIX}/src/shared/qbs/ HEAD > ${TEMPSOURCES}/__qtcreator_qbs.tar || exit 1
|
||||
|
||||
echo " Combining tar sources..."
|
||||
cd ${TEMPSOURCES} || exit 1
|
||||
tar xf __qtcreator_main.tar || exit 1
|
||||
tar xf __qtcreator_qbs.tar || exit 1
|
||||
tar czf "${RESULTDIR}/${PREFIX}.tar.gz" ${PREFIX}/ || exit 1
|
||||
tar cJf "${RESULTDIR}/${PREFIX}.tar.xz" ${PREFIX}/ || exit 1
|
||||
|
||||
echo "Creating zip archive..."
|
||||
echo " Filtering binary vs text files..."
|
||||
# write filter for text files (for use with 'file' command)
|
||||
echo ".*:.*ASCII
|
||||
.*:.*directory
|
||||
.*:.*empty
|
||||
.*:.*POSIX
|
||||
.*:.*html
|
||||
.*:.*text" > __txtpattern || exit 1
|
||||
# list all files
|
||||
find ${PREFIX} > __packagedfiles || exit 1
|
||||
# record file types
|
||||
file -f __packagedfiles > __filetypes || exit 1
|
||||
echo " Creating archive..."
|
||||
# zip text files and binary files separately
|
||||
cat __filetypes | grep -f __txtpattern -v | cut -d: -f1 | zip -9q "${RESULTDIR}/${PREFIX}.zip" -@ || exit 1
|
||||
cat __filetypes | grep -f __txtpattern | cut -d: -f1 | zip -l9q "${RESULTDIR}/${PREFIX}.zip" -@ || exit 1
|
||||
@@ -196,3 +196,9 @@ class Dumper(DumperBase):
|
||||
|
||||
def nativeDynamicTypeName(self, address, baseType):
|
||||
return None # FIXME: Seems sufficient, no idea why.
|
||||
|
||||
def callHelper(self, rettype, value, function, args):
|
||||
raise Exception("cdb does not support calling functions")
|
||||
|
||||
def putCallItem(self, name, rettype, value, func, *args):
|
||||
return
|
||||
|
||||
@@ -2999,6 +2999,8 @@ class DumperBase:
|
||||
return self.code in (TypeCodeIntegral, TypeCodeFloat, TypeCodeEnum)
|
||||
|
||||
def alignment(self):
|
||||
if self.code == TypeCodeTypedef:
|
||||
return self.stripTypedefs().alignment()
|
||||
if self.isSimpleType():
|
||||
if self.name == 'double':
|
||||
return self.dumper.ptrSize() # Crude approximation.
|
||||
@@ -3371,7 +3373,9 @@ class DumperBase:
|
||||
builder.addField(ptrSize, 'Q' if ptrSize == 8 else 'I')
|
||||
elif c == 'P': # Pointer as Value
|
||||
builder.addField(ptrSize, '%ss' % ptrSize)
|
||||
elif c in ('q', 'Q', 'd'):
|
||||
elif c in ('d'):
|
||||
builder.addField(8, c, fieldType = 'double')
|
||||
elif c in ('q', 'Q'):
|
||||
builder.addField(8, c)
|
||||
elif c in ('i', 'I', 'f'):
|
||||
builder.addField(4, c)
|
||||
|
||||
@@ -353,6 +353,7 @@ def qdump__QDateTime(d, value):
|
||||
|
||||
|
||||
def qdump__QDir(d, value):
|
||||
if not d.isMsvcTarget():
|
||||
d.putNumChild(1)
|
||||
privAddress = d.extractPointer(value)
|
||||
bit32 = d.ptrSize() == 4
|
||||
@@ -424,7 +425,7 @@ def qdump__QDir(d, value):
|
||||
absoluteDirEntryOffset = dirEntryOffset + fileSystemEntrySize
|
||||
|
||||
d.putStringValue(privAddress + dirEntryOffset)
|
||||
if d.isExpanded():
|
||||
if d.isExpanded() and not d.isMsvcTarget():
|
||||
with Children(d):
|
||||
ns = d.qtNamespace()
|
||||
d.call('int', value, 'count') # Fill cache.
|
||||
@@ -1042,7 +1043,7 @@ def qdump__QPixmap(d, value):
|
||||
else:
|
||||
(dummy, width, height) = d.split('pii', dataPtr)
|
||||
d.putValue('(%dx%d)' % (width, height))
|
||||
d.putNumChild(0)
|
||||
d.putPlainChildren(value)
|
||||
|
||||
|
||||
def qdump__QPoint(d, value):
|
||||
|
||||
@@ -213,12 +213,20 @@ def qform__std__map():
|
||||
|
||||
def qdump__std__map(d, value):
|
||||
if d.isQnxTarget():
|
||||
qdump__std__map__QNX(d, value)
|
||||
proxy, head, size = value.split('ppI')
|
||||
d.putItemCount(size)
|
||||
qdump_std__map__helper(d, size, value)
|
||||
return
|
||||
elif d.isMsvcTarget():
|
||||
proxy, head, size = value.split('ppQ')
|
||||
d.putItemCount(size)
|
||||
try:
|
||||
qdump_std__map__helper(d, size, value['_Mypair']['_Myval2']['_Myval2'])
|
||||
finally:
|
||||
return
|
||||
|
||||
# stuff is actually (color, pad) with 'I@', but we can save cycles/
|
||||
(compare, stuff, parent, left, right, size) = value.split('pppppp')
|
||||
impl = value["_M_t"]["_M_impl"]
|
||||
d.check(0 <= size and size <= 100*1000*1000)
|
||||
d.putItemCount(size)
|
||||
|
||||
@@ -226,7 +234,7 @@ def qdump__std__map(d, value):
|
||||
pairType = value.type[3][0]
|
||||
pairPointer = pairType.pointer()
|
||||
with PairedChildren(d, size, pairType=pairType, maxNumChild=1000):
|
||||
node = impl["_M_header"]["_M_left"]
|
||||
node = value["_M_t"]["_M_impl"]["_M_header"]["_M_left"]
|
||||
nodeSize = node.dereference().type.size()
|
||||
typeCode = "@{%s}@{%s}" % (pairType[0].name, pairType[1].name)
|
||||
for i in d.childRange():
|
||||
@@ -248,26 +256,23 @@ def qdump__std__map(d, value):
|
||||
break
|
||||
node = node["_M_left"]
|
||||
|
||||
def qdump__std__map__QNX(d, value):
|
||||
size = value['_Mysize']
|
||||
d.check(0 <= size and size <= 100*1000*1000)
|
||||
d.putItemCount(size)
|
||||
|
||||
def qdump_std__map__helper(d, size, value):
|
||||
if d.isExpanded():
|
||||
head = value['_Myhead']
|
||||
node = head['_Left']
|
||||
nodeType = head.type
|
||||
with Children(d, size, maxNumChild=1000):
|
||||
pairType = head.type[0]
|
||||
with PairedChildren(d, size, pairType=pairType, maxNumChild=1000):
|
||||
for i in d.childRange():
|
||||
pair = node.cast(nodeType).dereference()['_Myval']
|
||||
d.putPairItem(i, pair)
|
||||
if not node['_Right']['_Isnil']:
|
||||
if node['_Right']['_Isnil'].integer() == 0:
|
||||
node = node['_Right']
|
||||
while not node['_Left']['_Isnil']:
|
||||
while node['_Left']['_Isnil'].integer() == 0:
|
||||
node = node['_Left']
|
||||
else:
|
||||
parent = node['_Parent']
|
||||
while node == parent['_Right']['_Isnil']:
|
||||
while node and parent['_Right']['_Isnil'].integer() == 0:
|
||||
node = parent
|
||||
parent = parent['_Parent']
|
||||
if node['_Right'] != parent:
|
||||
@@ -794,7 +799,7 @@ def qedit__std__vector(d, value, data):
|
||||
gdb.execute(cmd)
|
||||
|
||||
def qdump__std__vector(d, value):
|
||||
if d.isQnxTarget():
|
||||
if d.isQnxTarget() or d.isMsvcTarget():
|
||||
qdumpHelper__std__vector__QNX(d, value)
|
||||
else:
|
||||
qdumpHelper__std__vector(d, value, False)
|
||||
@@ -835,20 +840,26 @@ def qdumpHelper__std__vector(d, value, isLibCpp):
|
||||
|
||||
def qdumpHelper__std__vector__QNX(d, value):
|
||||
innerType = value.type[0]
|
||||
isBool = str(innerType) == 'bool'
|
||||
isBool = innerType.name == 'bool'
|
||||
if isBool:
|
||||
try:
|
||||
impl = value['_Myvec']['_Mypair']['_Myval2']
|
||||
except:
|
||||
impl = value['_Myvec']
|
||||
start = impl['_Myfirst']
|
||||
last = impl['_Mylast']
|
||||
end = impl['_Myend']
|
||||
size = value['_Mysize']
|
||||
start = impl['_Myfirst'].pointer()
|
||||
last = impl['_Mylast'].pointer()
|
||||
end = impl['_Myend'].pointer()
|
||||
size = value['_Mysize'].integer()
|
||||
storagesize = start.dereference().type.size() * 8
|
||||
else:
|
||||
start = value['_Myfirst']
|
||||
last = value['_Mylast']
|
||||
end = value['_Myend']
|
||||
size = (last.integer() - start.integer()) / innerType.size()
|
||||
alloc = (end.integer() - start.integer()) / innerType.size()
|
||||
try:
|
||||
impl = value['_Mypair']['_Myval2']
|
||||
except:
|
||||
impl = value
|
||||
start = impl['_Myfirst'].pointer()
|
||||
last = impl['_Mylast'].pointer()
|
||||
end = impl['_Myend'].pointer()
|
||||
size = (last - start) // innerType.size()
|
||||
|
||||
d.check(0 <= size and size <= 1000 * 1000 * 1000)
|
||||
d.check(last <= end)
|
||||
@@ -863,11 +874,11 @@ def qdumpHelper__std__vector__QNX(d, value):
|
||||
for i in d.childRange():
|
||||
q = start + int(i / storagesize)
|
||||
with SubItem(d, i):
|
||||
d.putValue((q.dereference() >> (i % storagesize)) & 1)
|
||||
d.putValue((q.dereference().pointer() >> (i % storagesize)) & 1)
|
||||
d.putType("bool")
|
||||
d.putNumChild(0)
|
||||
else:
|
||||
d.putArrayData(start, size, innerType)
|
||||
d.putPlotData(start, size, innerType)
|
||||
|
||||
def qdump__std____1__vector(d, value):
|
||||
qdumpHelper__std__vector(d, value, True)
|
||||
|
||||
@@ -336,6 +336,10 @@ void ObjectNodeInstance::addToNewProperty(QObject *object, QObject *newParent, c
|
||||
list.append(object);
|
||||
} else if (isObject(property)) {
|
||||
property.write(objectToVariant(object));
|
||||
|
||||
if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
|
||||
if (QQuickItem *newParentItem = qobject_cast<QQuickItem *>(newParent))
|
||||
item->setParentItem(newParentItem);
|
||||
}
|
||||
|
||||
Q_ASSERT(objectToVariant(object).isValid());
|
||||
|
||||
@@ -190,8 +190,9 @@ Column {
|
||||
ButtonRowButton {
|
||||
iconSource: "images/icon_color_solid.png"
|
||||
onClicked: {
|
||||
colorEditor.backendValue.resetValue()
|
||||
gradientLine.deleteGradient()
|
||||
textField.text = colorEditor.color
|
||||
colorEditor.backendValue.resetValue()
|
||||
}
|
||||
tooltip: qsTr("Solid Color")
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ ComboBoxStyle {
|
||||
|
||||
}
|
||||
|
||||
padding.left: 20
|
||||
|
||||
background: Item {
|
||||
implicitWidth: 120
|
||||
implicitHeight: 24
|
||||
@@ -65,18 +67,14 @@ ComboBoxStyle {
|
||||
}
|
||||
}
|
||||
|
||||
label: Item {
|
||||
implicitWidth: textitem.implicitWidth + 20
|
||||
Text {
|
||||
label: Text {
|
||||
id: textitem
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: control.currentText
|
||||
renderType: Text.NativeRendering
|
||||
color: control.textColor
|
||||
}
|
||||
}
|
||||
|
||||
__dropDownStyle: MenuStyle {
|
||||
__maxPopupHeight: 600
|
||||
|
||||
@@ -133,6 +133,8 @@ Controls.TextField {
|
||||
event.accepted = true
|
||||
if (textField.completionActive) {
|
||||
listView.model = null
|
||||
} else {
|
||||
textField.rejected()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ Controls.ComboBox {
|
||||
model: ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"]
|
||||
|
||||
onModelChanged: {
|
||||
editText = backendValue.valueToString
|
||||
editText = comboBox.backendValue.valueToString
|
||||
}
|
||||
|
||||
style: CustomComboBoxStyle {
|
||||
@@ -50,7 +50,7 @@ Controls.ComboBox {
|
||||
ColorLogic {
|
||||
id: colorLogic
|
||||
backendValue: comboBox.backendValue
|
||||
property string textValue: backendValue.value
|
||||
property string textValue: comboBox.backendValue.valueToString
|
||||
onTextValueChanged: {
|
||||
comboBox.editText = textValue
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ Section {
|
||||
text: qsTr("Font")
|
||||
}
|
||||
FontComboBox {
|
||||
backendValue: fontFamily
|
||||
backendValue: fontSection.fontFamily
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
@@ -142,6 +142,30 @@ Section {
|
||||
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Font capitalization")
|
||||
toolTip: qsTr("Sets the capitalization for the text.")
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
Layout.fillWidth: true
|
||||
backendValue: backendValues.font_capitalization
|
||||
model: ["MixedCase", "AllUppercase", "AllLowercase", "SmallCaps", "Capitalize"]
|
||||
scope: "Font"
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Font weight")
|
||||
toolTip: qsTr("Sets the font's weight.")
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
Layout.fillWidth: true
|
||||
backendValue: backendValues.font_weight
|
||||
model: ["Normal", "Light", "ExtraLight", "Thin", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"]
|
||||
scope: "Font"
|
||||
}
|
||||
|
||||
Label {
|
||||
visible: showStyle
|
||||
text: qsTr("Style")
|
||||
@@ -154,5 +178,41 @@ Section {
|
||||
model: ["Normal", "Outline", "Raised", "Sunken"]
|
||||
scope: "Text"
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Spacing")
|
||||
}
|
||||
|
||||
SecondColumnLayout {
|
||||
Label {
|
||||
text: qsTr("Word")
|
||||
tooltip: qsTr("Sets the word spacing for the font.")
|
||||
width: 42
|
||||
}
|
||||
SpinBox {
|
||||
maximumValue: 9999999
|
||||
minimumValue: -9999999
|
||||
decimals: 0
|
||||
backendValue: backendValues.font_wordSpacing
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Item {
|
||||
width: 4
|
||||
height: 4
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Letter")
|
||||
tooltip: qsTr("Sets the letter spacing for the font.")
|
||||
width: 42
|
||||
}
|
||||
SpinBox {
|
||||
maximumValue: 9999999
|
||||
minimumValue: -9999999
|
||||
decimals: 0
|
||||
backendValue: backendValues.font_letterSpacing
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ Controls.TextField {
|
||||
|
||||
selectionColor: creatorTheme.PanelTextColorLight
|
||||
selectedTextColor: creatorTheme.PanelTextColorMid
|
||||
textColor: creatorTheme.PanelTextColorLight
|
||||
textColor: lineEdit.textColor
|
||||
placeholderTextColor: creatorTheme.PanelTextColorMid
|
||||
|
||||
padding.top: 3
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
import QtQuick 2.1
|
||||
import HelperWidgets 2.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Controls 1.0 as Controls
|
||||
|
||||
Section {
|
||||
caption: qsTr("Padding")
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
SectionLayout {
|
||||
Label {
|
||||
text: qsTr("Vertical")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
Label {
|
||||
text: qsTr("Top")
|
||||
tooltip: qsTr("Padding between the content and the top edge of the item.")
|
||||
width: 42
|
||||
}
|
||||
SpinBox {
|
||||
maximumValue: 9999999
|
||||
minimumValue: -9999999
|
||||
decimals: 0
|
||||
backendValue: backendValues.topPadding
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Item {
|
||||
width: 4
|
||||
height: 4
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Bottom")
|
||||
tooltip: qsTr("Padding between the content and the bottom edge of the item.")
|
||||
width: 42
|
||||
}
|
||||
SpinBox {
|
||||
maximumValue: 9999999
|
||||
minimumValue: -9999999
|
||||
decimals: 0
|
||||
backendValue: backendValues.bottomPadding
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Horizontal")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
Label {
|
||||
text: qsTr("Left")
|
||||
tooltip: qsTr("Padding between the content and the left edge of the item.")
|
||||
width: 42
|
||||
}
|
||||
SpinBox {
|
||||
maximumValue: 9999999
|
||||
minimumValue: -9999999
|
||||
decimals: 0
|
||||
backendValue: backendValues.leftPadding
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Item {
|
||||
width: 4
|
||||
height: 4
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Right")
|
||||
tooltip: qsTr("Padding between the content and the right edge of the item.")
|
||||
width: 42
|
||||
}
|
||||
SpinBox {
|
||||
maximumValue: 9999999
|
||||
minimumValue: -9999999
|
||||
decimals: 0
|
||||
backendValue: backendValues.rightPadding
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Padding")
|
||||
tooltip: qsTr("Padding between the content and the edges of the items.")
|
||||
}
|
||||
SecondColumnLayout {
|
||||
SpinBox {
|
||||
maximumValue: 9999999
|
||||
minimumValue: -9999999
|
||||
decimals: 0
|
||||
backendValue: backendValues.padding
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,9 +33,11 @@ Section {
|
||||
caption: qsTr("Text")
|
||||
|
||||
property bool showIsWrapping: false
|
||||
property bool showElide: false
|
||||
property bool showVerticalAlignment: false
|
||||
property bool useLineEdit: true
|
||||
property bool showFormatProperty: false
|
||||
property bool showFontSizeMode: false
|
||||
|
||||
SectionLayout {
|
||||
columns: 2
|
||||
@@ -62,6 +64,19 @@ Section {
|
||||
model: ["NoWrap", "WordWrap", "WrapAnywhere", "WrapAtWordBoundaryOrAnywhere"]
|
||||
}
|
||||
|
||||
Label {
|
||||
visible: showElide
|
||||
text: qsTr("Elide")
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
visible: showElide
|
||||
Layout.fillWidth: true
|
||||
backendValue: backendValues.elide
|
||||
scope: "Text"
|
||||
model: ["ElideNone", "ElideLeft", "ElideMiddle", "ElideRight"]
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Alignment")
|
||||
}
|
||||
@@ -91,5 +106,27 @@ Section {
|
||||
backendValue: backendValues.textFormat
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Render type")
|
||||
toolTip: qsTr("Override the default rendering type for this item.")
|
||||
}
|
||||
ComboBox {
|
||||
scope: "Text"
|
||||
model: ["QtRendering", "NativeRendering"]
|
||||
backendValue: backendValues.renderType
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Font size mode")
|
||||
toolTip: qsTr("Specifies how the font size of the displayed text is determined.")
|
||||
}
|
||||
ComboBox {
|
||||
scope: "Text"
|
||||
model: ["FixedSize", "HorizontalFit", "VerticalFit", "Fit"]
|
||||
backendValue: backendValues.fontSizeMode
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,13 @@ RowLayout {
|
||||
Controls.ComboBox {
|
||||
id: comboBox
|
||||
|
||||
ExtendedFunctionButton {
|
||||
x: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
backendValue: urlChooser.backendValue
|
||||
visible: comboBox.enabled
|
||||
}
|
||||
|
||||
property bool isComplete: false
|
||||
|
||||
function setCurrentText(text) {
|
||||
|
||||
@@ -38,3 +38,4 @@ Tab 2.0 Tab.qml
|
||||
TabView 2.0 TabView.qml
|
||||
ToolTipArea 2.0 ToolTipArea.qml
|
||||
UrlChooser 2.0 UrlChooser.qml
|
||||
PaddingSection 2.0 PaddingSection.qml
|
||||
|
||||
@@ -78,8 +78,8 @@ Rectangle {
|
||||
// right size after resizing to a wider width
|
||||
|
||||
Image {
|
||||
width: 16
|
||||
height: 16
|
||||
Layout.preferredWidth: 16
|
||||
Layout.preferredHeight: 16
|
||||
source: hasAliasExport ? "image://icons/alias-export-checked" : "image://icons/alias-export-unchecked"
|
||||
ToolTipArea {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -68,4 +68,8 @@ Column {
|
||||
|
||||
TextInputSection {
|
||||
}
|
||||
|
||||
PaddingSection {
|
||||
visible: minorQtQuickVersion > 5
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,4 +68,9 @@ Column {
|
||||
TextInputSection {
|
||||
isTextInput: true
|
||||
}
|
||||
|
||||
PaddingSection {
|
||||
visible: minorQtQuickVersion > 5
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ Column {
|
||||
showIsWrapping: true
|
||||
showVerticalAlignment: true
|
||||
showFormatProperty: true
|
||||
showElide: true
|
||||
showFontSizeMode: true
|
||||
}
|
||||
|
||||
Section {
|
||||
@@ -66,4 +68,8 @@ Column {
|
||||
FontSection {
|
||||
showStyle: true
|
||||
}
|
||||
|
||||
PaddingSection {
|
||||
visible: minorQtQuickVersion > 5
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
namespace ClangBackEnd {
|
||||
|
||||
LinePrefixer::LinePrefixer(const QByteArray &prefix)
|
||||
: m_prefix(prefix),
|
||||
m_previousIsEndingWithNewLine(true)
|
||||
: m_prefix(prefix)
|
||||
{}
|
||||
|
||||
void LinePrefixer::setPrefix(const QByteArray &prefix)
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
|
||||
private:
|
||||
QByteArray m_prefix;
|
||||
bool m_previousIsEndingWithNewLine;
|
||||
bool m_previousIsEndingWithNewLine = true;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -101,25 +101,22 @@ static inline std::string fixInnerType(const std::string &type,
|
||||
// Return size from an STL vector (last/first iterators).
|
||||
static inline int msvcStdVectorSize(const SymbolGroupValue &v)
|
||||
{
|
||||
// MSVC2012 has 2 base classes, MSVC2010 1, MSVC2008 none
|
||||
if (const SymbolGroupValue myFirstPtrV = SymbolGroupValue::findMember(v, "_Myfirst")) {
|
||||
if (const SymbolGroupValue myLastPtrV = myFirstPtrV.parent()["_Mylast"]) {
|
||||
const ULONG64 firstPtr = myFirstPtrV.pointerValue();
|
||||
const ULONG64 lastPtr = myLastPtrV.pointerValue();
|
||||
const ULONG64 firstPtr = v.readPointerValueFromAncestor("_Myfirst");
|
||||
const ULONG64 lastPtr = v.readPointerValueFromAncestor("_Mylast");
|
||||
if (!firstPtr || lastPtr < firstPtr)
|
||||
return -1;
|
||||
const std::vector<std::string> innerTypes = v.innerTypes();
|
||||
if (innerTypes.empty())
|
||||
return -1;
|
||||
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(innerTypes[0]), v);
|
||||
const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
|
||||
if (size == 0)
|
||||
return -1;
|
||||
if (lastPtr == firstPtr)
|
||||
return 0;
|
||||
// Subtract the pointers: We need to do the pointer arithmetics ourselves
|
||||
// as we get char *pointers.
|
||||
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v);
|
||||
const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
|
||||
if (size == 0)
|
||||
return -1;
|
||||
return static_cast<int>((lastPtr - firstPtr) / size);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return size of container or -1
|
||||
@@ -193,10 +190,12 @@ int containerSize(KnownType kt, const SymbolGroupValue &v)
|
||||
case KT_StdMap:
|
||||
case KT_StdMultiMap:
|
||||
case KT_StdValArray:
|
||||
case KT_StdList:
|
||||
if (const SymbolGroupValue size = SymbolGroupValue::findMember(v, "_Mysize"))
|
||||
return size.intValue();
|
||||
case KT_StdList: {
|
||||
const int size = v.readIntegerFromAncestor("_Mysize");
|
||||
if (size >= 0)
|
||||
return size;
|
||||
break;
|
||||
}
|
||||
case KT_StdStack:
|
||||
if (const SymbolGroupValue deque = v[unsigned(0)])
|
||||
return containerSize(KT_StdDeque, deque);
|
||||
|
||||
@@ -53,11 +53,30 @@ PyObject *lookupType(const std::string &typeNameIn)
|
||||
{
|
||||
std::string typeName = typeNameIn;
|
||||
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
|
||||
std::string fullTypeName = typeName;
|
||||
// GetSymbolTypeId doesn't support pointer types so we need to strip off the '*' first
|
||||
while (endsWith(typeName, '*'))
|
||||
typeName.pop_back();
|
||||
ULONG64 module;
|
||||
ULONG typeId;
|
||||
if (FAILED(symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module)))
|
||||
Py_RETURN_NONE;
|
||||
return createType(module, typeId);
|
||||
if (typeName != fullTypeName) {
|
||||
if (module == 0) { // found some builtin type like char so we take the first module available to look up the pointer type
|
||||
ULONG loaded, unloaded;
|
||||
if (FAILED(symbols->GetNumberModules(&loaded, &unloaded)))
|
||||
Py_RETURN_NONE;
|
||||
if ((loaded + unloaded == 0) || FAILED(symbols->GetModuleByIndex(0, &module)))
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
if (FAILED(symbols->GetTypeId(module, fullTypeName.c_str(), &typeId)))
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
size_t typeNameLength = fullTypeName.length();
|
||||
char *cTypeName = new char[typeNameLength + 1];
|
||||
fullTypeName.copy(cTypeName, fullTypeName.length());
|
||||
cTypeName[typeNameLength] = 0;
|
||||
return createType(module, typeId, cTypeName);
|
||||
}
|
||||
|
||||
char *getTypeName(ULONG64 module, ULONG typeId)
|
||||
@@ -93,7 +112,9 @@ PyObject *type_bitSize(Type *self)
|
||||
{
|
||||
ULONG size;
|
||||
auto extcmd = ExtensionCommandContext::instance();
|
||||
if (FAILED(extcmd->symbols()->GetTypeSize(self->m_module, self->m_typeId, &size)))
|
||||
if (endsWith(getTypeName(self), '*'))
|
||||
size = SUCCEEDED(ExtensionCommandContext::instance()->control()->IsPointer64Bit()) ? 8 : 4;
|
||||
else if (FAILED(extcmd->symbols()->GetTypeSize(self->m_module, self->m_typeId, &size)))
|
||||
return NULL;
|
||||
return Py_BuildValue("k", size * 8);
|
||||
}
|
||||
@@ -143,13 +164,8 @@ PyObject *type_Target(Type *self)
|
||||
Py_XINCREF(self);
|
||||
return (PyObject *)self;
|
||||
}
|
||||
typeName = typeName.substr(0, typeName.length() - 1);
|
||||
|
||||
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
|
||||
ULONG typeId;
|
||||
if (FAILED(symbols->GetTypeId(self->m_module, typeName.c_str(), &typeId)))
|
||||
return NULL;
|
||||
return createType(self->m_module, typeId);
|
||||
typeName.pop_back();
|
||||
return lookupType(typeName);
|
||||
}
|
||||
|
||||
PyObject *type_StripTypedef(Type *self)
|
||||
@@ -241,7 +257,7 @@ PyObject *type_TemplateArgument(Type *self, PyObject *args)
|
||||
if (innerTypes.size() <= index)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
const std::string &innerType = innerTypes.at(index);
|
||||
const std::string &innerType = SymbolGroupValue::stripConst(innerTypes.at(index));
|
||||
if (numeric) {
|
||||
try {
|
||||
return Py_BuildValue("i", std::stoi(innerType));
|
||||
@@ -270,12 +286,12 @@ void type_Dealloc(Type *self)
|
||||
delete[] self->m_name;
|
||||
}
|
||||
|
||||
PyObject *createType(ULONG64 module, ULONG typeId)
|
||||
PyObject *createType(ULONG64 module, ULONG typeId, char* name)
|
||||
{
|
||||
Type *type = PyObject_New(Type, type_pytype());
|
||||
type->m_module = module;
|
||||
type->m_typeId = typeId;
|
||||
type->m_name = nullptr;
|
||||
type->m_name = name;
|
||||
return reinterpret_cast<PyObject *>(type);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,4 +44,4 @@ PyTypeObject *type_pytype();
|
||||
char *getTypeName(ULONG64 module, ULONG typeId);
|
||||
|
||||
PyObject *lookupType(const std::string &typeName);
|
||||
PyObject *createType(ULONG64 module, ULONG typeId);
|
||||
PyObject *createType(ULONG64 module, ULONG typeId, char *name = nullptr);
|
||||
|
||||
@@ -154,6 +154,15 @@ int SymbolGroupValue::readIntegerFromAncestor(const std::string &name, int defau
|
||||
return readPODFromAncestor<int>(name, defaultValue);
|
||||
}
|
||||
|
||||
ULONG64 SymbolGroupValue::offsetOfChild(const SymbolGroupValue &child) const
|
||||
{
|
||||
const ULONG64 base = isPointerType(type()) ? pointerValue() : address();
|
||||
const ULONG64 childAddress = child.address();
|
||||
if (base == 0 || childAddress == 0)
|
||||
return 0;
|
||||
return childAddress - base;
|
||||
}
|
||||
|
||||
LONG64 SymbolGroupValue::offsetOfAncestor(const std::string &name) const
|
||||
{
|
||||
return infoOfAncestor(name).offset;
|
||||
@@ -204,7 +213,7 @@ SymbolAncestorInfo SymbolGroupValue::infoOfAncestor(const std::string &name) con
|
||||
continue;
|
||||
info = child.infoOfAncestor(name);
|
||||
if (info.isValid()) {
|
||||
info.offset += offsetOfAncestor(child.name());
|
||||
info.offset += offsetOfChild(child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
SymbolGroupValue operator[](const char *name) const;
|
||||
SymbolGroupValue operator[](unsigned) const;
|
||||
unsigned childCount() const;
|
||||
ULONG64 offsetOfChild(const SymbolGroupValue &child) const;
|
||||
SymbolGroupValue parent() const;
|
||||
// take address and cast to desired (pointer) type
|
||||
SymbolGroupValue typeCast(const char *type) const;
|
||||
|
||||
@@ -269,7 +269,8 @@ QStringList Environment::appendExeExtensions(const QString &executable) const
|
||||
}
|
||||
|
||||
FileName Environment::searchInPath(const QString &executable,
|
||||
const QStringList &additionalDirs) const
|
||||
const QStringList &additionalDirs,
|
||||
bool (*func)(const QString &name)) const
|
||||
{
|
||||
if (executable.isEmpty())
|
||||
return FileName();
|
||||
@@ -292,7 +293,7 @@ FileName Environment::searchInPath(const QString &executable,
|
||||
continue;
|
||||
alreadyChecked.insert(dir);
|
||||
FileName tmp = searchInDirectory(execs, dir);
|
||||
if (!tmp.isEmpty())
|
||||
if (!tmp.isEmpty() && (!func || func(tmp.toString())))
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -304,7 +305,7 @@ FileName Environment::searchInPath(const QString &executable,
|
||||
continue;
|
||||
alreadyChecked.insert(p);
|
||||
FileName tmp = searchInDirectory(execs, QDir::fromNativeSeparators(p));
|
||||
if (!tmp.isEmpty())
|
||||
if (!tmp.isEmpty() && (!func || func(tmp.toString())))
|
||||
return tmp;
|
||||
}
|
||||
return FileName();
|
||||
|
||||
@@ -100,7 +100,9 @@ public:
|
||||
Environment::const_iterator constFind(const QString &name) const;
|
||||
|
||||
FileName searchInPath(const QString &executable,
|
||||
const QStringList &additionalDirs = QStringList()) const;
|
||||
const QStringList &additionalDirs = QStringList(),
|
||||
bool (*func)(const QString &name) = nullptr) const;
|
||||
|
||||
QStringList path() const;
|
||||
QStringList appendExeExtensions(const QString &executable) const;
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 160 B |
BIN
src/libs/utils/images/editcopy@2x.png
Normal file
|
After Width: | Height: | Size: 196 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 249 B |
BIN
src/libs/utils/images/editcut@2x.png
Normal file
|
After Width: | Height: | Size: 470 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 154 B |
BIN
src/libs/utils/images/editpaste@2x.png
Normal file
|
After Width: | Height: | Size: 214 B |
|
Before Width: | Height: | Size: 977 B After Width: | Height: | Size: 134 B |
BIN
src/libs/utils/images/filenew@2x.png
Normal file
|
After Width: | Height: | Size: 158 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 134 B |
BIN
src/libs/utils/images/fileopen@2x.png
Normal file
|
After Width: | Height: | Size: 209 B |
|
Before Width: | Height: | Size: 134 B After Width: | Height: | Size: 135 B |
|
Before Width: | Height: | Size: 222 B After Width: | Height: | Size: 222 B |
|
Before Width: | Height: | Size: 132 B After Width: | Height: | Size: 131 B |
|
Before Width: | Height: | Size: 211 B After Width: | Height: | Size: 211 B |
@@ -38,11 +38,16 @@
|
||||
<file>images/compile_error_taskbar@2x.png</file>
|
||||
<file>images/dir.png</file>
|
||||
<file>images/editcopy.png</file>
|
||||
<file>images/editcopy@2x.png</file>
|
||||
<file>images/editcut.png</file>
|
||||
<file>images/editcut@2x.png</file>
|
||||
<file>images/editpaste.png</file>
|
||||
<file>images/editpaste@2x.png</file>
|
||||
<file>images/empty14.png</file>
|
||||
<file>images/filenew.png</file>
|
||||
<file>images/filenew@2x.png</file>
|
||||
<file>images/fileopen.png</file>
|
||||
<file>images/fileopen@2x.png</file>
|
||||
<file>images/filesave.png</file>
|
||||
<file>images/filesave@2x.png</file>
|
||||
<file>images/inputfield.png</file>
|
||||
|
||||
@@ -64,10 +64,10 @@ const Icon BOOKMARK_TOOLBAR({
|
||||
const Icon BOOKMARK_TEXTEDITOR({
|
||||
{QLatin1String(":/utils/images/bookmark.png"), Theme::Bookmarks_TextMarkColor}}, Icon::Tint);
|
||||
|
||||
const Icon NEWFILE(
|
||||
QLatin1String(":/utils/images/filenew.png"));
|
||||
const Icon OPENFILE(
|
||||
QLatin1String(":/utils/images/fileopen.png"));
|
||||
const Icon NEWFILE({
|
||||
{QLatin1String(":/utils/images/filenew.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||
const Icon OPENFILE({
|
||||
{QLatin1String(":/utils/images/fileopen.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||
const Icon SAVEFILE({
|
||||
{QLatin1String(":/utils/images/filesave.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||
const Icon SAVEFILE_TOOLBAR({
|
||||
@@ -76,12 +76,12 @@ const Icon UNDO({
|
||||
{QLatin1String(":/utils/images/undo.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||
const Icon REDO({
|
||||
{QLatin1String(":/utils/images/redo.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||
const Icon COPY(
|
||||
QLatin1String(":/utils/images/editcopy.png"));
|
||||
const Icon PASTE(
|
||||
QLatin1String(":/utils/images/editpaste.png"));
|
||||
const Icon CUT(
|
||||
QLatin1String(":/utils/images/editcut.png"));
|
||||
const Icon COPY({
|
||||
{QLatin1String(":/utils/images/editcopy.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||
const Icon PASTE({
|
||||
{QLatin1String(":/utils/images/editpaste.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||
const Icon CUT({
|
||||
{QLatin1String(":/utils/images/editcut.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||
const Icon DIR(
|
||||
QLatin1String(":/utils/images/dir.png"));
|
||||
const Icon RESET({
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>397</width>
|
||||
<height>205</height>
|
||||
<width>449</width>
|
||||
<height>210</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -17,16 +17,8 @@
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="runDisabledGTestsCB">
|
||||
<property name="toolTip">
|
||||
<string>Executes disabled tests when performing a test run.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Run disabled tests</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="breakOnFailureCB">
|
||||
<property name="toolTip">
|
||||
<string>Turn failures into debugger breakpoints.</string>
|
||||
@@ -39,35 +31,30 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="repeatGTestsCB">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="runDisabledGTestsCB">
|
||||
<property name="toolTip">
|
||||
<string>Repeats a test run (you might be required to increase the timeout to avoid canceling the tests).</string>
|
||||
<string>Executes disabled tests when performing a test run.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Repeat tests</string>
|
||||
<string>Run disabled tests</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="throwOnFailureCB">
|
||||
<property name="toolTip">
|
||||
<string>Turn assertion failures into C++ exceptions.</string>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
<property name="text">
|
||||
<string>Throw on failure</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
@@ -77,7 +64,27 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="shuffleGTestsCB">
|
||||
<property name="toolTip">
|
||||
<string>Shuffle tests automatically on every iteration by the given seed.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shuffle tests</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="repeatGTestsCB">
|
||||
<property name="toolTip">
|
||||
<string>Repeats a test run (you might be required to increase the timeout to avoid canceling the tests).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Repeat tests</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="repetitionSpin">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
@@ -90,50 +97,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="shuffleGTestsCB">
|
||||
<property name="toolTip">
|
||||
<string>Shuffle tests automatically on every iteration by the given seed.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shuffle tests</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
@@ -143,7 +110,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="seedSpin">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
@@ -159,31 +126,8 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="throwOnFailureCB">
|
||||
<property name="toolTip">
|
||||
<string>Turn assertion failures into C++ exceptions.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Throw on failure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -36,9 +36,6 @@
|
||||
<property name="title">
|
||||
<string>Benchmark Metrics</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="walltimeRB">
|
||||
|
||||
@@ -237,7 +237,7 @@ QList<TestConfiguration *> QuickTestTreeItem::getSelectedTestConfigurations() co
|
||||
int grandChildCount = child->childCount();
|
||||
for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) {
|
||||
const TestTreeItem *grandChild = child->childItem(grandChildRow);
|
||||
if (grandChild->type() != TestFunctionOrSet)
|
||||
if (grandChild->checked() != Qt::Checked || grandChild->type() != TestFunctionOrSet)
|
||||
continue;
|
||||
testFunctions << child->name() + "::" + grandChild->name();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ QtcPlugin {
|
||||
"bookmark.h",
|
||||
"bookmarkmanager.cpp",
|
||||
"bookmarkmanager.h",
|
||||
"bookmarks.qrc",
|
||||
"bookmarks_global.h",
|
||||
"bookmarksplugin.cpp",
|
||||
"bookmarksplugin.h",
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringList>
|
||||
|
||||
using namespace ClangCodeModel;
|
||||
@@ -100,7 +99,7 @@ public:
|
||||
|
||||
optionsBuilder.addPredefinedMacrosAndHeaderPathsOptions();
|
||||
optionsBuilder.addWrappedQtHeadersIncludePath();
|
||||
optionsBuilder.addHeaderPathOptions(/*addAsNativePath*/ true);
|
||||
optionsBuilder.addHeaderPathOptions();
|
||||
optionsBuilder.addProjectConfigFileInclude();
|
||||
|
||||
optionsBuilder.addMsvcCompatibilityVersion();
|
||||
@@ -118,18 +117,12 @@ private:
|
||||
|
||||
bool excludeHeaderPath(const QString &path) const override
|
||||
{
|
||||
if (m_projectPart.toolchainType == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) {
|
||||
if (path.contains(QLatin1String("lib/gcc/i686-apple-darwin")))
|
||||
return true;
|
||||
}
|
||||
|
||||
// We already provide a custom clang include path matching the used libclang version,
|
||||
// so better ignore the clang include paths from the system as this might lead to an
|
||||
// unfavorable order with regard to include_next.
|
||||
static QRegularExpression clangIncludeDir(
|
||||
QLatin1String("\\A.*/lib/clang/\\d+\\.\\d+(\\.\\d+)?/include\\z"));
|
||||
if (clangIncludeDir.match(path).hasMatch())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return CompilerOptionsBuilder::excludeHeaderPath(path);
|
||||
}
|
||||
|
||||
void addPredefinedMacrosAndHeaderPathsOptions()
|
||||
|
||||
@@ -56,18 +56,12 @@ RefactoringCompilerOptionsBuilder::RefactoringCompilerOptionsBuilder(CppTools::P
|
||||
|
||||
bool RefactoringCompilerOptionsBuilder::excludeHeaderPath(const QString &path) const
|
||||
{
|
||||
if (m_projectPart.toolchainType == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) {
|
||||
if (path.contains(QLatin1String("lib/gcc/i686-apple-darwin")))
|
||||
return true;
|
||||
}
|
||||
|
||||
// We already provide a custom clang include path matching the used libclang version,
|
||||
// so better ignore the clang include paths from the system as this might lead to an
|
||||
// unfavorable order with regard to include_next.
|
||||
static QRegularExpression clangIncludeDir(
|
||||
QLatin1String("\\A.*/lib/clang/\\d+\\.\\d+(\\.\\d+)?/include\\z"));
|
||||
if (clangIncludeDir.match(path).hasMatch())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return CompilerOptionsBuilder::excludeHeaderPath(path);
|
||||
}
|
||||
|
||||
void RefactoringCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptions()
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace ClangRefactoring {
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@ void ClangStaticAnalyzerPreconfiguredSessionTests::testPreconfiguredSession()
|
||||
QSignalSpy waitUntilAnalyzerFinished(&m_analyzerTool, SIGNAL(finished(bool)));
|
||||
QVERIFY(waitUntilAnalyzerFinished.wait(30000));
|
||||
const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst();
|
||||
QVERIFY(arguments.first().toBool());
|
||||
const bool analyzerFinishedSuccessfully = arguments.first().toBool();
|
||||
QVERIFY(analyzerFinishedSuccessfully);
|
||||
QCOMPARE(m_analyzerTool.diagnostics().count(), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ public:
|
||||
const Core::Id type = projectPart.toolchainType;
|
||||
if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|
||||
|| type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID)
|
||||
optionsBuilder.addDefine("#define _X86INTRIN_H_INCLUDED\n");
|
||||
optionsBuilder.addDefine("#define _X86INTRIN_H_INCLUDED");
|
||||
|
||||
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
||||
optionsBuilder.addDefines(projectPart.toolchainDefines);
|
||||
|
||||
@@ -63,7 +63,7 @@ static QStringList constructCommandLineArguments(const QString &filePath,
|
||||
arguments
|
||||
<< QLatin1String("--analyze")
|
||||
<< QLatin1String("-o")
|
||||
<< logFile
|
||||
<< QDir::toNativeSeparators(logFile)
|
||||
;
|
||||
arguments += options;
|
||||
arguments << QDir::toNativeSeparators(filePath);
|
||||
@@ -80,7 +80,7 @@ ClangStaticAnalyzerRunner::ClangStaticAnalyzerRunner(const QString &clangExecuta
|
||||
const Utils::Environment &environment,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_clangExecutable(clangExecutable)
|
||||
, m_clangExecutable(QDir::toNativeSeparators(clangExecutable))
|
||||
, m_clangLogFileDir(clangLogFileDir)
|
||||
{
|
||||
QTC_CHECK(!m_clangExecutable.isEmpty());
|
||||
|
||||
@@ -1970,6 +1970,7 @@ void EditorManagerPrivate::autoSave()
|
||||
if (!errors.isEmpty())
|
||||
QMessageBox::critical(ICore::mainWindow(), tr("File Error"),
|
||||
errors.join(QLatin1Char('\n')));
|
||||
emit m_instance->autoSaved();
|
||||
}
|
||||
|
||||
void EditorManagerPrivate::handleContextChange(const QList<IContext *> &context)
|
||||
|
||||
@@ -185,6 +185,7 @@ signals:
|
||||
void editorsClosed(QList<Core::IEditor *> editors);
|
||||
void findOnFileSystemRequest(const QString &path);
|
||||
void aboutToSave(IDocument *document);
|
||||
void autoSaved();
|
||||
|
||||
public slots:
|
||||
static void saveDocument();
|
||||
|
||||
@@ -68,11 +68,6 @@ void InfoBarEntry::setCancelButtonInfo(const QString &_cancelButtonText, CallBac
|
||||
m_cancelButtonCallBack = callBack;
|
||||
}
|
||||
|
||||
void InfoBarEntry::setSuppressionButtonInfo(InfoBarEntry::CallBack callback)
|
||||
{
|
||||
m_suppressionButtonCallBack = callback;
|
||||
}
|
||||
|
||||
void InfoBarEntry::setShowDefaultCancelButton(bool yesno)
|
||||
{
|
||||
m_showDefaultCancelButton = yesno;
|
||||
@@ -282,9 +277,7 @@ void InfoBarDisplay::update()
|
||||
if (info.globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) {
|
||||
infoWidgetSuppressButton = new QToolButton;
|
||||
infoWidgetSuppressButton->setText(tr("Do Not Show Again"));
|
||||
connect(infoWidgetSuppressButton, &QAbstractButton::clicked, this, [this, info, id] {
|
||||
if (info.m_suppressionButtonCallBack)
|
||||
info.m_suppressionButtonCallBack();
|
||||
connect(infoWidgetSuppressButton, &QAbstractButton::clicked, this, [this, id] {
|
||||
m_infoBar->removeInfo(id);
|
||||
InfoBar::globallySuppressInfo(id);
|
||||
});
|
||||
|
||||
@@ -58,7 +58,6 @@ public:
|
||||
void setCustomButtonInfo(const QString &_buttonText, CallBack callBack);
|
||||
void setCancelButtonInfo(CallBack callBack);
|
||||
void setCancelButtonInfo(const QString &_cancelButtonText, CallBack callBack);
|
||||
void setSuppressionButtonInfo(CallBack callback);
|
||||
void setShowDefaultCancelButton(bool yesno);
|
||||
|
||||
using DetailsWidgetCreator = std::function<QWidget*()>;
|
||||
@@ -71,7 +70,6 @@ private:
|
||||
CallBack m_buttonCallBack;
|
||||
QString cancelButtonText;
|
||||
CallBack m_cancelButtonCallBack;
|
||||
CallBack m_suppressionButtonCallBack;
|
||||
GlobalSuppressionMode globalSuppression;
|
||||
DetailsWidgetCreator m_detailsWidgetCreator;
|
||||
bool m_showDefaultCancelButton = true;
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include <cpptools/cpptoolsconstants.h>
|
||||
#include <cpptools/cpptoolsplugin.h>
|
||||
#include <cpptools/cpptoolsreuse.h>
|
||||
#include <cpptools/cpptoolssettings.h>
|
||||
#include <cpptools/cppworkingcopy.h>
|
||||
#include <cpptools/symbolfinder.h>
|
||||
#include <cpptools/refactoringengineinterface.h>
|
||||
@@ -130,7 +131,7 @@ public:
|
||||
QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
|
||||
|
||||
QToolButton *m_preprocessorButton = nullptr;
|
||||
QToolButton *m_headerErrorsIndicatorButton = nullptr;
|
||||
QAction *m_headerErrorsIndicatorAction = nullptr;
|
||||
|
||||
CppSelectionChanger m_cppSelectionChanger;
|
||||
|
||||
@@ -229,15 +230,20 @@ void CppEditorWidget::finalizeInitialization()
|
||||
connect(cmd, &Command::keySequenceChanged, this, &CppEditorWidget::updatePreprocessorButtonTooltip);
|
||||
updatePreprocessorButtonTooltip();
|
||||
connect(d->m_preprocessorButton, &QAbstractButton::clicked, this, &CppEditorWidget::showPreProcessorWidget);
|
||||
|
||||
d->m_headerErrorsIndicatorButton = new QToolButton(this);
|
||||
d->m_headerErrorsIndicatorButton->setIcon(Utils::Icons::WARNING_TOOLBAR.pixmap());
|
||||
connect(d->m_headerErrorsIndicatorButton, &QAbstractButton::clicked,
|
||||
this, &CppEditorWidget::showHeaderErrorInfoBar);
|
||||
d->m_headerErrorsIndicatorButton->setEnabled(false);
|
||||
|
||||
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_preprocessorButton);
|
||||
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_headerErrorsIndicatorButton);
|
||||
|
||||
auto *headerErrorsIndicatorButton = new QToolButton(this);
|
||||
headerErrorsIndicatorButton->setToolTip(tr("Show First Error in Included Files"));
|
||||
headerErrorsIndicatorButton->setIcon(Utils::Icons::WARNING_TOOLBAR.pixmap());
|
||||
connect(headerErrorsIndicatorButton, &QAbstractButton::clicked, []() {
|
||||
CppToolsSettings::instance()->setShowHeaderErrorInfoBar(true);
|
||||
});
|
||||
d->m_headerErrorsIndicatorAction = insertExtraToolBarWidget(TextEditorWidget::Left,
|
||||
headerErrorsIndicatorButton);
|
||||
d->m_headerErrorsIndicatorAction->setVisible(false);
|
||||
connect(CppToolsSettings::instance(), &CppToolsSettings::showHeaderErrorInfoBarChanged,
|
||||
this, &CppEditorWidget::updateHeaderErrorWidgets);
|
||||
|
||||
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_cppEditorOutline->widget());
|
||||
}
|
||||
|
||||
@@ -252,6 +258,10 @@ void CppEditorWidget::finalizeInitializationAfterDuplication(TextEditorWidget *o
|
||||
d->m_cppEditorOutline->update();
|
||||
const Id selectionKind = CodeWarningsSelection;
|
||||
setExtraSelections(selectionKind, cppEditorWidget->extraSelections(selectionKind));
|
||||
|
||||
d->m_headerErrorDiagnosticWidgetCreator
|
||||
= cppEditorWidget->d->m_headerErrorDiagnosticWidgetCreator;
|
||||
updateHeaderErrorWidgets();
|
||||
}
|
||||
|
||||
CppEditorWidget::~CppEditorWidget()
|
||||
@@ -329,13 +339,14 @@ void CppEditorWidget::updateHeaderErrorWidgets()
|
||||
infoBar->removeInfo(id);
|
||||
|
||||
if (d->m_headerErrorDiagnosticWidgetCreator) {
|
||||
if (infoBar->canInfoBeAdded(id)) {
|
||||
addHeaderErrorInfoBarEntryAndHideIndicator();
|
||||
if (CppToolsSettings::instance()->showHeaderErrorInfoBar()) {
|
||||
addHeaderErrorInfoBarEntry();
|
||||
d->m_headerErrorsIndicatorAction->setVisible(false);
|
||||
} else {
|
||||
d->m_headerErrorsIndicatorButton->setEnabled(true);
|
||||
d->m_headerErrorsIndicatorAction->setVisible(true);
|
||||
}
|
||||
} else {
|
||||
d->m_headerErrorsIndicatorButton->setEnabled(false);
|
||||
d->m_headerErrorsIndicatorAction->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,23 +445,20 @@ void CppEditorWidget::renameSymbolUnderCursorBuiltin()
|
||||
renameUsages(); // Rename non-local symbol or macro
|
||||
}
|
||||
|
||||
void CppEditorWidget::addHeaderErrorInfoBarEntryAndHideIndicator() const
|
||||
void CppEditorWidget::addHeaderErrorInfoBarEntry() const
|
||||
{
|
||||
InfoBarEntry info(Constants::ERRORS_IN_HEADER_FILES,
|
||||
tr("<b>Warning</b>: The code model could not parse an included file, "
|
||||
"which might lead to slow or incorrect code completion and "
|
||||
"highlighting, for example."),
|
||||
InfoBarEntry::GlobalSuppressionEnabled);
|
||||
"highlighting, for example."));
|
||||
info.setDetailsWidgetCreator(d->m_headerErrorDiagnosticWidgetCreator);
|
||||
info.setShowDefaultCancelButton(false);
|
||||
info.setSuppressionButtonInfo([this](){
|
||||
d->m_headerErrorsIndicatorButton->setEnabled(true);
|
||||
info.setCustomButtonInfo("Minimize", [](){
|
||||
CppToolsSettings::instance()->setShowHeaderErrorInfoBar(false);
|
||||
});
|
||||
|
||||
InfoBar *infoBar = textDocument()->infoBar();
|
||||
infoBar->addInfo(info);
|
||||
|
||||
d->m_headerErrorsIndicatorButton->setEnabled(false);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -1024,14 +1032,5 @@ void CppEditorWidget::showPreProcessorWidget()
|
||||
}
|
||||
}
|
||||
|
||||
void CppEditorWidget::showHeaderErrorInfoBar()
|
||||
{
|
||||
const Id id(Constants::ERRORS_IN_HEADER_FILES);
|
||||
QTC_CHECK(!textDocument()->infoBar()->canInfoBeAdded(id));
|
||||
|
||||
InfoBar::globallyUnsuppressInfo(id);
|
||||
addHeaderErrorInfoBarEntryAndHideIndicator();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CppEditor
|
||||
|
||||
@@ -31,10 +31,6 @@
|
||||
|
||||
#include <QScopedPointer>
|
||||
|
||||
namespace Core {
|
||||
class InfoBarEntry;
|
||||
}
|
||||
|
||||
namespace CppTools {
|
||||
class CppEditorOutline;
|
||||
class RefactoringEngineInterface;
|
||||
@@ -91,7 +87,6 @@ public:
|
||||
|
||||
void switchDeclarationDefinition(bool inNextSplit);
|
||||
void showPreProcessorWidget();
|
||||
void showHeaderErrorInfoBar();
|
||||
|
||||
void findUsages();
|
||||
void renameSymbolUnderCursor();
|
||||
@@ -150,7 +145,7 @@ private:
|
||||
void renameSymbolUnderCursorClang();
|
||||
void renameSymbolUnderCursorBuiltin();
|
||||
|
||||
void addHeaderErrorInfoBarEntryAndHideIndicator() const;
|
||||
void addHeaderErrorInfoBarEntry() const;
|
||||
|
||||
CppTools::ProjectPart *projectPart() const;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
@@ -100,7 +101,7 @@ void CompilerOptionsBuilder::enableExceptions()
|
||||
add(QLatin1String("-fexceptions"));
|
||||
}
|
||||
|
||||
void CompilerOptionsBuilder::addHeaderPathOptions(bool addAsNativePath)
|
||||
void CompilerOptionsBuilder::addHeaderPathOptions()
|
||||
{
|
||||
typedef ProjectPartHeaderPath HeaderPath;
|
||||
const QString defaultPrefix = includeOption();
|
||||
@@ -126,10 +127,7 @@ void CompilerOptionsBuilder::addHeaderPathOptions(bool addAsNativePath)
|
||||
break;
|
||||
}
|
||||
|
||||
QString path = prefix + headerPath.path;
|
||||
path = addAsNativePath ? QDir::toNativeSeparators(path) : path;
|
||||
|
||||
result.append(path);
|
||||
result.append(prefix + QDir::toNativeSeparators(headerPath.path));
|
||||
}
|
||||
|
||||
m_options.append(result);
|
||||
@@ -393,7 +391,15 @@ bool CompilerOptionsBuilder::excludeDefineLine(const QByteArray &defineLine) con
|
||||
|
||||
bool CompilerOptionsBuilder::excludeHeaderPath(const QString &headerPath) const
|
||||
{
|
||||
Q_UNUSED(headerPath);
|
||||
// A clang tool chain might have another version and passing in the
|
||||
// intrinsics path from that version will lead to errors (unknown
|
||||
// intrinsics, unfavorable order with regard to include_next).
|
||||
if (m_projectPart.toolchainType == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) {
|
||||
static QRegularExpression clangIncludeDir(
|
||||
QLatin1String("\\A.*/lib/clang/\\d+\\.\\d+(\\.\\d+)?/include\\z"));
|
||||
return clangIncludeDir.match(headerPath).hasMatch();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
// Add options based on project part
|
||||
virtual void addTargetTriple();
|
||||
virtual void enableExceptions();
|
||||
void addHeaderPathOptions(bool addAsNativePath = false);
|
||||
void addHeaderPathOptions();
|
||||
void addToolchainAndProjectDefines();
|
||||
void addDefines(const QByteArray &defineDirectives);
|
||||
virtual void addLanguageOption(ProjectFile::Kind fileKind);
|
||||
|
||||
@@ -49,6 +49,7 @@ const char CPPTOOLS_SETTINGSGROUP[] = "CppTools";
|
||||
const char LOWERCASE_CPPFILES_KEY[] = "LowerCaseFiles";
|
||||
enum { lowerCaseFilesDefault = 1 };
|
||||
const char CPPTOOLS_SORT_EDITOR_DOCUMENT_OUTLINE[] = "SortedMethodOverview";
|
||||
const char CPPTOOLS_SHOW_INFO_BAR_FOR_HEADER_ERRORS[] = "ShowInfoBarForHeaderErrors";
|
||||
const char CPPTOOLS_MODEL_MANAGER_PCH_USAGE[] = "PCHUsage";
|
||||
const char CPPTOOLS_SKIP_INDEXING_BIG_FILES[] = "SkipIndexingBigFiles";
|
||||
const char CPPTOOLS_INDEXER_FILE_SIZE_LIMIT[] = "IndexerFileSizeLimit";
|
||||
|
||||
@@ -267,3 +267,21 @@ void CppToolsSettings::setSortedEditorDocumentOutline(bool sorted)
|
||||
ICore::settings()->setValue(sortEditorDocumentOutlineKey(), sorted);
|
||||
emit editorDocumentOutlineSortingChanged(sorted);
|
||||
}
|
||||
|
||||
static QString showHeaderErrorInfoBarKey()
|
||||
{
|
||||
return QLatin1String(CppTools::Constants::CPPTOOLS_SETTINGSGROUP)
|
||||
+ QLatin1Char('/')
|
||||
+ QLatin1String(CppTools::Constants::CPPTOOLS_SHOW_INFO_BAR_FOR_HEADER_ERRORS);
|
||||
}
|
||||
|
||||
bool CppToolsSettings::showHeaderErrorInfoBar() const
|
||||
{
|
||||
return ICore::settings()->value(showHeaderErrorInfoBarKey(), true).toBool();
|
||||
}
|
||||
|
||||
void CppToolsSettings::setShowHeaderErrorInfoBar(bool show)
|
||||
{
|
||||
ICore::settings()->setValue(showHeaderErrorInfoBarKey(), show);
|
||||
emit showHeaderErrorInfoBarChanged(show);
|
||||
}
|
||||
|
||||
@@ -63,8 +63,12 @@ public:
|
||||
bool sortedEditorDocumentOutline() const;
|
||||
void setSortedEditorDocumentOutline(bool sorted);
|
||||
|
||||
bool showHeaderErrorInfoBar() const;
|
||||
void setShowHeaderErrorInfoBar(bool show);
|
||||
|
||||
signals:
|
||||
void editorDocumentOutlineSortingChanged(bool isSorted);
|
||||
void showHeaderErrorInfoBarChanged(bool isShown);
|
||||
|
||||
private:
|
||||
Internal::CppToolsSettingsPrivate *d;
|
||||
|
||||
@@ -2374,6 +2374,7 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro
|
||||
QTC_ASSERT(parent, return);
|
||||
LookupItems itemsToLookup;
|
||||
|
||||
const QSet<QString> expandedINames = engine->watchHandler()->expandedINames();
|
||||
foreach (const QVariant &property, properties) {
|
||||
QmlV8ObjectData propertyData = extractData(property);
|
||||
auto item = new WatchItem;
|
||||
@@ -2395,7 +2396,7 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro
|
||||
item->id = propertyData.handle;
|
||||
item->type = propertyData.type;
|
||||
item->value = propertyData.value.toString();
|
||||
if (item->type.isEmpty())
|
||||
if (item->type.isEmpty() || expandedINames.contains(item->iname))
|
||||
itemsToLookup.insert(propertyData.handle, {item->iname, item->name, item->exp});
|
||||
item->setHasChildren(propertyData.properties.count() > 0);
|
||||
parent->appendChild(item);
|
||||
|
||||
@@ -33,7 +33,8 @@ HEADERS += \
|
||||
iosdeploystep.h \
|
||||
iosdeploystepfactory.h \
|
||||
iosdeploystepwidget.h \
|
||||
iosanalyzesupport.h
|
||||
iosanalyzesupport.h \
|
||||
simulatorcontrol.h
|
||||
|
||||
|
||||
SOURCES += \
|
||||
@@ -61,7 +62,8 @@ SOURCES += \
|
||||
iosdeploystep.cpp \
|
||||
iosdeploystepfactory.cpp \
|
||||
iosdeploystepwidget.cpp \
|
||||
iosanalyzesupport.cpp
|
||||
iosanalyzesupport.cpp \
|
||||
simulatorcontrol.cpp
|
||||
|
||||
FORMS += \
|
||||
iossettingswidget.ui \
|
||||
|
||||
@@ -69,6 +69,8 @@ QtcPlugin {
|
||||
"iossimulatorfactory.cpp",
|
||||
"iossimulatorfactory.h",
|
||||
"iostoolhandler.cpp",
|
||||
"iostoolhandler.h"
|
||||
"iostoolhandler.h",
|
||||
"simulatorcontrol.cpp",
|
||||
"simulatorcontrol.h"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "iosconstants.h"
|
||||
#include "iosdevice.h"
|
||||
#include "iossimulator.h"
|
||||
#include "simulatorcontrol.h"
|
||||
#include "iosprobe.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -332,7 +333,7 @@ void IosConfigurations::updateSimulators()
|
||||
dev = IDevice::ConstPtr(new IosSimulator(devId));
|
||||
devManager->addDevice(dev);
|
||||
}
|
||||
IosSimulator::updateAvailableDevices();
|
||||
SimulatorControl::updateAvailableSimulators();
|
||||
}
|
||||
|
||||
void IosConfigurations::setDeveloperPath(const FileName &devPath)
|
||||
|
||||
@@ -169,6 +169,8 @@ IosDebugSupport::IosDebugSupport(IosRunConfiguration *runConfig,
|
||||
m_runner, &IosRunner::start);
|
||||
connect(m_runControl, &RunControl::finished,
|
||||
m_runner, &IosRunner::stop);
|
||||
connect(m_runControl, &DebuggerRunControl::stateChanged,
|
||||
m_runner, &IosRunner::debuggerStateChanged);
|
||||
|
||||
connect(m_runner, &IosRunner::gotServerPorts,
|
||||
this, &IosDebugSupport::handleServerPorts);
|
||||
|
||||
@@ -101,7 +101,12 @@ bool IosDeployStep::init(QList<const BuildStep *> &earlierSteps)
|
||||
this->target()->activeRunConfiguration());
|
||||
QTC_ASSERT(runConfig, return false);
|
||||
m_bundlePath = runConfig->bundleDirectory().toString();
|
||||
if (m_device.isNull()) {
|
||||
|
||||
if (iosdevice()) {
|
||||
m_deviceType = IosDeviceType(IosDeviceType::IosDevice, deviceId());
|
||||
} else if (iossimulator()) {
|
||||
m_deviceType = runConfig->deviceType();
|
||||
} else {
|
||||
emit addOutput(tr("Error: no device available, deploy failed."),
|
||||
BuildStep::ErrorMessageOutput);
|
||||
return false;
|
||||
@@ -113,17 +118,15 @@ void IosDeployStep::run(QFutureInterface<bool> &fi)
|
||||
{
|
||||
m_futureInterface = fi;
|
||||
QTC_CHECK(m_transferStatus == NoTransfer);
|
||||
if (iosdevice().isNull()) {
|
||||
if (iossimulator().isNull())
|
||||
if (device().isNull()) {
|
||||
TaskHub::addTask(Task::Error, tr("Deployment failed. No iOS device found."),
|
||||
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
|
||||
reportRunResult(m_futureInterface, !iossimulator().isNull());
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
m_toolHandler = new IosToolHandler(m_deviceType, this);
|
||||
m_transferStatus = TransferInProgress;
|
||||
QTC_CHECK(m_toolHandler == 0);
|
||||
m_toolHandler = new IosToolHandler(IosDeviceType(IosDeviceType::IosDevice), this);
|
||||
m_futureInterface.setProgressRange(0, 200);
|
||||
m_futureInterface.setProgressValueAndText(0, QLatin1String("Transferring application"));
|
||||
m_futureInterface.reportStarted();
|
||||
@@ -136,7 +139,7 @@ void IosDeployStep::run(QFutureInterface<bool> &fi)
|
||||
connect(m_toolHandler, &IosToolHandler::errorMsg,
|
||||
this, &IosDeployStep::handleErrorMsg);
|
||||
checkProvisioningProfile();
|
||||
m_toolHandler->requestTransferApp(appBundle(), deviceId());
|
||||
m_toolHandler->requestTransferApp(appBundle(), m_deviceType.identifier);
|
||||
}
|
||||
|
||||
void IosDeployStep::cancel()
|
||||
@@ -150,7 +153,7 @@ void IosDeployStep::cleanup()
|
||||
QTC_CHECK(m_transferStatus != TransferInProgress);
|
||||
m_transferStatus = NoTransfer;
|
||||
m_device.clear();
|
||||
m_toolHandler = 0;
|
||||
m_toolHandler = nullptr;
|
||||
m_expectFail = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ private:
|
||||
QFutureInterface<bool> m_futureInterface;
|
||||
ProjectExplorer::IDevice::ConstPtr m_device;
|
||||
QString m_bundlePath;
|
||||
IosDeviceType m_deviceType;
|
||||
static const Core::Id Id;
|
||||
bool m_expectFail;
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "iosconstants.h"
|
||||
#include "iosmanager.h"
|
||||
#include "iosdeploystep.h"
|
||||
#include "simulatorcontrol.h"
|
||||
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/target.h>
|
||||
@@ -346,7 +347,7 @@ IosDeviceType IosRunConfiguration::deviceType() const
|
||||
{
|
||||
QList<IosDeviceType> availableSimulators;
|
||||
if (m_deviceType.type == IosDeviceType::SimulatedDevice)
|
||||
availableSimulators = IosSimulator::availableDevices();
|
||||
availableSimulators = SimulatorControl::availableSimulators();
|
||||
if (!availableSimulators.isEmpty()) {
|
||||
QList<IosDeviceType> elegibleDevices;
|
||||
QString devname = m_deviceType.identifier.split(QLatin1Char(',')).value(0);
|
||||
@@ -417,7 +418,7 @@ void IosRunConfigurationWidget::updateValues()
|
||||
m_deviceTypeLabel->setVisible(showDeviceSelector);
|
||||
m_deviceTypeComboBox->setVisible(showDeviceSelector);
|
||||
if (showDeviceSelector && m_deviceTypeModel.rowCount() == 0) {
|
||||
foreach (const IosDeviceType &dType, IosSimulator::availableDevices()) {
|
||||
foreach (const IosDeviceType &dType, SimulatorControl::availableSimulators()) {
|
||||
QStandardItem *item = new QStandardItem(dType.displayName);
|
||||
QVariant v;
|
||||
v.setValue(dType);
|
||||
|
||||
@@ -168,6 +168,12 @@ void IosRunner::stop()
|
||||
}
|
||||
}
|
||||
|
||||
void IosRunner::debuggerStateChanged(Debugger::DebuggerState state)
|
||||
{
|
||||
if (m_toolHandler)
|
||||
m_toolHandler->debuggerStateChanged(state);
|
||||
}
|
||||
|
||||
void IosRunner::handleDidStartApp(IosToolHandler *handler, const QString &bundlePath,
|
||||
const QString &deviceId, IosToolHandler::OpStatus status)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "iostoolhandler.h"
|
||||
#include "iossimulator.h"
|
||||
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
#include <qmldebug/qmldebugcommandlinearguments.h>
|
||||
|
||||
@@ -64,6 +65,9 @@ public:
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
public slots:
|
||||
void debuggerStateChanged(Debugger::DebuggerState state);
|
||||
|
||||
signals:
|
||||
void didStartApp(Ios::IosToolHandler::OpStatus status);
|
||||
void gotServerPorts(Utils::Port gdbPort, Utils::Port qmlPort);
|
||||
|
||||
@@ -45,9 +45,6 @@ static const QLatin1String iosDeviceTypeDisplayNameKey = QLatin1String("displayN
|
||||
static const QLatin1String iosDeviceTypeTypeKey = QLatin1String("type");
|
||||
static const QLatin1String iosDeviceTypeIdentifierKey = QLatin1String("identifier");
|
||||
|
||||
QMutex IosSimulator::_mutex;
|
||||
QList<IosDeviceType> IosSimulator::_availableDevices;
|
||||
|
||||
IosSimulator::IosSimulator(Core::Id id)
|
||||
: IDevice(Core::Id(Constants::IOS_SIMULATOR_TYPE),
|
||||
IDevice::AutoDetected,
|
||||
@@ -124,48 +121,6 @@ IDevice::Ptr IosSimulator::clone() const
|
||||
return IDevice::Ptr(new IosSimulator(*this));
|
||||
}
|
||||
|
||||
QList<IosDeviceType> IosSimulator::availableDevices()
|
||||
{
|
||||
QMutexLocker l(&_mutex);
|
||||
return _availableDevices;
|
||||
}
|
||||
|
||||
void IosSimulator::setAvailableDevices(QList<IosDeviceType> value)
|
||||
{
|
||||
QMutexLocker l(&_mutex);
|
||||
_availableDevices = value;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void handleDeviceInfo(Ios::IosToolHandler *handler, const QString &deviceId,
|
||||
const Ios::IosToolHandler::Dict &info)
|
||||
{
|
||||
Q_UNUSED(deviceId);
|
||||
QList<IosDeviceType> res;
|
||||
QMapIterator<QString, QString> i(info);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
IosDeviceType simulatorType(IosDeviceType::SimulatedDevice);
|
||||
simulatorType.displayName = i.value();
|
||||
simulatorType.identifier = i.key();
|
||||
QStringList ids = i.key().split(QLatin1Char(','));
|
||||
if (ids.length() > 1)
|
||||
simulatorType.displayName += QLatin1String(", iOS ") + ids.last().trimmed();
|
||||
res.append(simulatorType);
|
||||
}
|
||||
handler->deleteLater();
|
||||
std::stable_sort(res.begin(), res.end());
|
||||
IosSimulator::setAvailableDevices(res);
|
||||
}
|
||||
}
|
||||
|
||||
void IosSimulator::updateAvailableDevices()
|
||||
{
|
||||
IosToolHandler *toolHandler = new IosToolHandler(IosDeviceType(IosDeviceType::SimulatedDevice));
|
||||
QObject::connect(toolHandler, &IosToolHandler::deviceInfo, &handleDeviceInfo);
|
||||
toolHandler->requestDeviceInfo(QString());
|
||||
}
|
||||
|
||||
void IosSimulator::fromMap(const QVariantMap &map)
|
||||
{
|
||||
IDevice::fromMap(map);
|
||||
|
||||
@@ -67,10 +67,6 @@ public:
|
||||
typedef QSharedPointer<IosSimulator> Ptr;
|
||||
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
|
||||
|
||||
static QList<IosDeviceType> availableDevices();
|
||||
static void setAvailableDevices(QList<IosDeviceType> value);
|
||||
static void updateAvailableDevices();
|
||||
|
||||
QString displayType() const override;
|
||||
ProjectExplorer::IDeviceWidget *createWidget() override;
|
||||
QList<Core::Id> actionIds() const override;
|
||||
@@ -91,8 +87,6 @@ protected:
|
||||
IosSimulator(const IosSimulator &other);
|
||||
private:
|
||||
mutable quint16 m_lastPort;
|
||||
static QMutex _mutex;
|
||||
static QList<IosDeviceType> _availableDevices;
|
||||
};
|
||||
|
||||
namespace IosKitInformation {
|
||||
|
||||
@@ -27,13 +27,18 @@
|
||||
#include "iosconfigurations.h"
|
||||
#include "iosconstants.h"
|
||||
#include "iossimulator.h"
|
||||
#include "simulatorcontrol.h"
|
||||
|
||||
#include "debugger/debuggerconstants.h"
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QProcess>
|
||||
@@ -52,6 +57,8 @@ namespace Ios {
|
||||
|
||||
namespace Internal {
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
struct ParserState {
|
||||
enum Kind {
|
||||
Msg,
|
||||
@@ -132,7 +139,8 @@ public:
|
||||
virtual void requestDeviceInfo(const QString &deviceId, int timeout = 1000) = 0;
|
||||
bool isRunning();
|
||||
void start(const QString &exe, const QStringList &args);
|
||||
void stop(int errorCode);
|
||||
virtual void stop(int errorCode) = 0;
|
||||
virtual void debuggerStateChanged(Debugger::DebuggerState state) { Q_UNUSED(state); }
|
||||
|
||||
// signals
|
||||
void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress,
|
||||
@@ -148,15 +156,12 @@ public:
|
||||
void appOutput(const QString &output);
|
||||
void errorMsg(const QString &msg);
|
||||
void toolExited(int code);
|
||||
// slots
|
||||
void subprocessError(QProcess::ProcessError error);
|
||||
void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void subprocessHasData();
|
||||
void killProcess();
|
||||
virtual bool expectsFileDescriptor() = 0;
|
||||
protected:
|
||||
void processXml();
|
||||
|
||||
protected:
|
||||
void killProcess();
|
||||
|
||||
|
||||
protected:
|
||||
IosToolHandler *q;
|
||||
QProcess *process;
|
||||
QTimer killTimer;
|
||||
@@ -176,34 +181,56 @@ class IosDeviceToolHandlerPrivate : public IosToolHandlerPrivate
|
||||
{
|
||||
public:
|
||||
explicit IosDeviceToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q);
|
||||
virtual void requestTransferApp(const QString &bundlePath, const QString &deviceId,
|
||||
int timeout = 1000);
|
||||
virtual void requestRunApp(const QString &bundlePath, const QStringList &extraArgs,
|
||||
|
||||
// IosToolHandlerPrivate overrides
|
||||
public:
|
||||
void requestTransferApp(const QString &bundlePath, const QString &deviceId,
|
||||
int timeout = 1000) override;
|
||||
void requestRunApp(const QString &bundlePath, const QStringList &extraArgs,
|
||||
IosToolHandler::RunKind runKind,
|
||||
const QString &deviceId, int timeout = 1000);
|
||||
virtual void requestDeviceInfo(const QString &deviceId, int timeout = 1000);
|
||||
virtual bool expectsFileDescriptor();
|
||||
const QString &deviceId, int timeout = 1000) override;
|
||||
void requestDeviceInfo(const QString &deviceId, int timeout = 1000) override;
|
||||
void stop(int errorCode) override;
|
||||
|
||||
private:
|
||||
void subprocessError(QProcess::ProcessError error);
|
||||
void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void subprocessHasData();
|
||||
void processXml();
|
||||
};
|
||||
|
||||
class IosSimulatorToolHandlerPrivate : public IosToolHandlerPrivate
|
||||
{
|
||||
public:
|
||||
explicit IosSimulatorToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q);
|
||||
virtual void requestTransferApp(const QString &bundlePath, const QString &deviceId,
|
||||
int timeout = 1000);
|
||||
virtual void requestRunApp(const QString &bundlePath, const QStringList &extraArgs,
|
||||
|
||||
// IosToolHandlerPrivate overrides
|
||||
public:
|
||||
void requestTransferApp(const QString &bundlePath, const QString &deviceIdentifier,
|
||||
int timeout = 1000) override;
|
||||
void requestRunApp(const QString &bundlePath, const QStringList &extraArgs,
|
||||
IosToolHandler::RunKind runKind,
|
||||
const QString &deviceId, int timeout = 1000);
|
||||
virtual void requestDeviceInfo(const QString &deviceId, int timeout = 1000);
|
||||
virtual bool expectsFileDescriptor();
|
||||
const QString &deviceIdentifier, int timeout = 1000) override;
|
||||
void requestDeviceInfo(const QString &deviceId, int timeout = 1000) override;
|
||||
void stop(int errorCode) override;
|
||||
void debuggerStateChanged(Debugger::DebuggerState state) override;
|
||||
|
||||
private:
|
||||
void addDeviceArguments(QStringList &args) const;
|
||||
void simAppProcessError(QProcess::ProcessError error);
|
||||
void simAppProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void simAppProcessHasData();
|
||||
void simAppProcessHasErrorOutput();
|
||||
void launchAppOnSimulator();
|
||||
|
||||
private:
|
||||
qint64 appPId = -1;
|
||||
bool appLaunched = false;
|
||||
};
|
||||
|
||||
IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType,
|
||||
Ios::IosToolHandler *q) :
|
||||
q(q),
|
||||
process(new QProcess),
|
||||
process(nullptr),
|
||||
state(NonStarted),
|
||||
devType(devType),
|
||||
iBegin(0),
|
||||
@@ -211,34 +238,6 @@ IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType,
|
||||
gdbSocket(-1)
|
||||
{
|
||||
killTimer.setSingleShot(true);
|
||||
QProcessEnvironment env(QProcessEnvironment::systemEnvironment());
|
||||
foreach (const QString &k, env.keys())
|
||||
if (k.startsWith(QLatin1String("DYLD_")))
|
||||
env.remove(k);
|
||||
QStringList frameworkPaths;
|
||||
Utils::FileName xcPath = IosConfigurations::developerPath();
|
||||
QString privateFPath = xcPath.appendPath(QLatin1String("Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks")).toFileInfo().canonicalFilePath();
|
||||
if (!privateFPath.isEmpty())
|
||||
frameworkPaths << privateFPath;
|
||||
QString otherFPath = xcPath.appendPath(QLatin1String("../OtherFrameworks")).toFileInfo().canonicalFilePath();
|
||||
if (!otherFPath.isEmpty())
|
||||
frameworkPaths << otherFPath;
|
||||
QString sharedFPath = xcPath.appendPath(QLatin1String("../SharedFrameworks")).toFileInfo().canonicalFilePath();
|
||||
if (!sharedFPath.isEmpty())
|
||||
frameworkPaths << sharedFPath;
|
||||
frameworkPaths << QLatin1String("/System/Library/Frameworks")
|
||||
<< QLatin1String("/System/Library/PrivateFrameworks");
|
||||
env.insert(QLatin1String("DYLD_FALLBACK_FRAMEWORK_PATH"), frameworkPaths.join(QLatin1Char(':')));
|
||||
qCDebug(toolHandlerLog) << "IosToolHandler runEnv:" << env.toStringList();
|
||||
process->setProcessEnvironment(env);
|
||||
QObject::connect(process, &QProcess::readyReadStandardOutput,
|
||||
q, &IosToolHandler::subprocessHasData);
|
||||
QObject::connect(process,
|
||||
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
q, &IosToolHandler::subprocessFinished);
|
||||
QObject::connect(process, &QProcess::errorOccurred, q, &IosToolHandler::subprocessError);
|
||||
QObject::connect(&killTimer, &QTimer::timeout,
|
||||
q, &IosToolHandler::killProcess);
|
||||
}
|
||||
|
||||
IosToolHandlerPrivate::~IosToolHandlerPrivate()
|
||||
@@ -258,6 +257,7 @@ bool IosToolHandlerPrivate::isRunning()
|
||||
|
||||
void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args)
|
||||
{
|
||||
Q_ASSERT(process);
|
||||
QTC_CHECK(state == NonStarted);
|
||||
state = Starting;
|
||||
qCDebug(toolHandlerLog) << "running " << exe << args;
|
||||
@@ -265,44 +265,6 @@ void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args)
|
||||
state = StartedInferior;
|
||||
}
|
||||
|
||||
void IosToolHandlerPrivate::stop(int errorCode)
|
||||
{
|
||||
qCDebug(toolHandlerLog) << "IosToolHandlerPrivate::stop";
|
||||
State oldState = state;
|
||||
state = Stopped;
|
||||
switch (oldState) {
|
||||
case NonStarted:
|
||||
qCWarning(toolHandlerLog) << "IosToolHandler::stop() when state was NonStarted";
|
||||
// pass
|
||||
case Starting:
|
||||
switch (op){
|
||||
case OpNone:
|
||||
qCWarning(toolHandlerLog) << "IosToolHandler::stop() when op was OpNone";
|
||||
break;
|
||||
case OpAppTransfer:
|
||||
didTransferApp(bundlePath, deviceId, IosToolHandler::Failure);
|
||||
break;
|
||||
case OpAppRun:
|
||||
didStartApp(bundlePath, deviceId, IosToolHandler::Failure);
|
||||
break;
|
||||
case OpDeviceInfo:
|
||||
break;
|
||||
}
|
||||
// pass
|
||||
case StartedInferior:
|
||||
case XmlEndProcessed:
|
||||
toolExited(errorCode);
|
||||
break;
|
||||
case Stopped:
|
||||
return;
|
||||
}
|
||||
if (isRunning()) {
|
||||
process->write("k\n\r");
|
||||
process->closeWriteChannel();
|
||||
killTimer.start(1500);
|
||||
}
|
||||
}
|
||||
|
||||
// signals
|
||||
void IosToolHandlerPrivate::isTransferringApp(const QString &bundlePath, const QString &deviceId,
|
||||
int progress, int maxProgress, const QString &info)
|
||||
@@ -355,7 +317,7 @@ void IosToolHandlerPrivate::toolExited(int code)
|
||||
emit q->toolExited(q, code);
|
||||
}
|
||||
|
||||
void IosToolHandlerPrivate::subprocessError(QProcess::ProcessError error)
|
||||
void IosDeviceToolHandlerPrivate::subprocessError(QProcess::ProcessError error)
|
||||
{
|
||||
if (state != Stopped)
|
||||
errorMsg(IosToolHandler::tr("iOS tool Error %1").arg(error));
|
||||
@@ -366,7 +328,7 @@ void IosToolHandlerPrivate::subprocessError(QProcess::ProcessError error)
|
||||
}
|
||||
}
|
||||
|
||||
void IosToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
void IosDeviceToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
stop((exitStatus == QProcess::NormalExit) ? exitCode : -1 );
|
||||
qCDebug(toolHandlerLog) << "IosToolHandler::finished(" << this << ")";
|
||||
@@ -374,7 +336,7 @@ void IosToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatu
|
||||
emit q->finished(q);
|
||||
}
|
||||
|
||||
void IosToolHandlerPrivate::processXml()
|
||||
void IosDeviceToolHandlerPrivate::processXml()
|
||||
{
|
||||
while (!outputParser.atEnd()) {
|
||||
QXmlStreamReader::TokenType tt = outputParser.readNext();
|
||||
@@ -556,7 +518,7 @@ void IosToolHandlerPrivate::processXml()
|
||||
}
|
||||
}
|
||||
|
||||
void IosToolHandlerPrivate::subprocessHasData()
|
||||
void IosDeviceToolHandlerPrivate::subprocessHasData()
|
||||
{
|
||||
qCDebug(toolHandlerLog) << "subprocessHasData, state:" << state;
|
||||
while (true) {
|
||||
@@ -596,7 +558,42 @@ void IosToolHandlerPrivate::subprocessHasData()
|
||||
IosDeviceToolHandlerPrivate::IosDeviceToolHandlerPrivate(const IosDeviceType &devType,
|
||||
IosToolHandler *q)
|
||||
: IosToolHandlerPrivate(devType, q)
|
||||
{ }
|
||||
{
|
||||
process = new QProcess;
|
||||
|
||||
// Prepare & set process Environment.
|
||||
QProcessEnvironment env(QProcessEnvironment::systemEnvironment());
|
||||
foreach (const QString &k, env.keys())
|
||||
if (k.startsWith(QLatin1String("DYLD_")))
|
||||
env.remove(k);
|
||||
QStringList frameworkPaths;
|
||||
Utils::FileName xcPath = IosConfigurations::developerPath();
|
||||
QString privateFPath = xcPath.appendPath(QLatin1String("Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks")).toFileInfo().canonicalFilePath();
|
||||
if (!privateFPath.isEmpty())
|
||||
frameworkPaths << privateFPath;
|
||||
QString otherFPath = xcPath.appendPath(QLatin1String("../OtherFrameworks")).toFileInfo().canonicalFilePath();
|
||||
if (!otherFPath.isEmpty())
|
||||
frameworkPaths << otherFPath;
|
||||
QString sharedFPath = xcPath.appendPath(QLatin1String("../SharedFrameworks")).toFileInfo().canonicalFilePath();
|
||||
if (!sharedFPath.isEmpty())
|
||||
frameworkPaths << sharedFPath;
|
||||
frameworkPaths << QLatin1String("/System/Library/Frameworks")
|
||||
<< QLatin1String("/System/Library/PrivateFrameworks");
|
||||
env.insert(QLatin1String("DYLD_FALLBACK_FRAMEWORK_PATH"), frameworkPaths.join(QLatin1Char(':')));
|
||||
qCDebug(toolHandlerLog) << "IosToolHandler runEnv:" << env.toStringList();
|
||||
process->setProcessEnvironment(env);
|
||||
|
||||
QObject::connect(process, &QProcess::readyReadStandardOutput,
|
||||
std::bind(&IosDeviceToolHandlerPrivate::subprocessHasData,this));
|
||||
|
||||
QObject::connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
std::bind(&IosDeviceToolHandlerPrivate::subprocessFinished,this, _1,_2));
|
||||
|
||||
QObject::connect(process, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
|
||||
std::bind(&IosDeviceToolHandlerPrivate::subprocessError, this, _1));
|
||||
|
||||
QObject::connect(&killTimer, &QTimer::timeout, std::bind(&IosDeviceToolHandlerPrivate::killProcess, this));
|
||||
}
|
||||
|
||||
void IosDeviceToolHandlerPrivate::requestTransferApp(const QString &bundlePath,
|
||||
const QString &deviceId, int timeout)
|
||||
@@ -644,11 +641,46 @@ void IosDeviceToolHandlerPrivate::requestDeviceInfo(const QString &deviceId, int
|
||||
start(IosToolHandler::iosDeviceToolPath(), args);
|
||||
}
|
||||
|
||||
bool IosDeviceToolHandlerPrivate::expectsFileDescriptor()
|
||||
|
||||
void IosDeviceToolHandlerPrivate::stop(int errorCode)
|
||||
{
|
||||
return op == OpAppRun && runKind == IosToolHandler::DebugRun;
|
||||
qCDebug(toolHandlerLog) << "IosToolHandlerPrivate::stop";
|
||||
State oldState = state;
|
||||
state = Stopped;
|
||||
switch (oldState) {
|
||||
case NonStarted:
|
||||
qCWarning(toolHandlerLog) << "IosToolHandler::stop() when state was NonStarted";
|
||||
// pass
|
||||
case Starting:
|
||||
switch (op){
|
||||
case OpNone:
|
||||
qCWarning(toolHandlerLog) << "IosToolHandler::stop() when op was OpNone";
|
||||
break;
|
||||
case OpAppTransfer:
|
||||
didTransferApp(bundlePath, deviceId, IosToolHandler::Failure);
|
||||
break;
|
||||
case OpAppRun:
|
||||
didStartApp(bundlePath, deviceId, IosToolHandler::Failure);
|
||||
break;
|
||||
case OpDeviceInfo:
|
||||
break;
|
||||
}
|
||||
// pass
|
||||
case StartedInferior:
|
||||
case XmlEndProcessed:
|
||||
toolExited(errorCode);
|
||||
break;
|
||||
case Stopped:
|
||||
return;
|
||||
}
|
||||
if (isRunning()) {
|
||||
process->write("k\n\r");
|
||||
process->closeWriteChannel();
|
||||
killTimer.start(1500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// IosSimulatorToolHandlerPrivate
|
||||
|
||||
IosSimulatorToolHandlerPrivate::IosSimulatorToolHandlerPrivate(const IosDeviceType &devType,
|
||||
@@ -657,64 +689,159 @@ IosSimulatorToolHandlerPrivate::IosSimulatorToolHandlerPrivate(const IosDeviceTy
|
||||
{ }
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::requestTransferApp(const QString &bundlePath,
|
||||
const QString &deviceId, int timeout)
|
||||
const QString &deviceIdentifier, int timeout)
|
||||
{
|
||||
Q_UNUSED(timeout);
|
||||
this->bundlePath = bundlePath;
|
||||
this->deviceId = deviceId;
|
||||
emit didTransferApp(bundlePath, deviceId, IosToolHandler::Success);
|
||||
this->deviceId = deviceIdentifier;
|
||||
isTransferringApp(bundlePath, deviceId, 0, 100, "");
|
||||
if (SimulatorControl::startSimulator(deviceId)) {
|
||||
isTransferringApp(bundlePath, deviceId, 20, 100, "");
|
||||
QByteArray cmdOutput;
|
||||
if (SimulatorControl::installApp(deviceId, Utils::FileName::fromString(bundlePath), cmdOutput)) {
|
||||
isTransferringApp(bundlePath, deviceId, 100, 100, "");
|
||||
didTransferApp(bundlePath, deviceId, IosToolHandler::Success);
|
||||
} else {
|
||||
errorMsg(IosToolHandler::tr("Application install on Simulator failed. %1").arg(QString::fromLocal8Bit(cmdOutput)));
|
||||
didTransferApp(bundlePath, deviceId, IosToolHandler::Failure);
|
||||
}
|
||||
} else {
|
||||
errorMsg(IosToolHandler::tr("Application install on Simulator failed. Simulator not running."));
|
||||
didTransferApp(bundlePath, deviceId, IosToolHandler::Failure);
|
||||
}
|
||||
emit q->finished(q);
|
||||
}
|
||||
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::requestRunApp(const QString &bundlePath,
|
||||
const QStringList &extraArgs,
|
||||
IosToolHandler::RunKind runType,
|
||||
const QString &deviceId, int timeout)
|
||||
const QString &deviceIdentifier, int timeout)
|
||||
{
|
||||
Q_UNUSED(timeout);
|
||||
Q_UNUSED(deviceIdentifier);
|
||||
this->bundlePath = bundlePath;
|
||||
this->deviceId = deviceId;
|
||||
this->deviceId = devType.identifier;
|
||||
this->runKind = runType;
|
||||
QStringList args;
|
||||
|
||||
args << QLatin1String("launch") << bundlePath;
|
||||
Utils::FileName devPath = IosConfigurations::developerPath();
|
||||
if (!devPath.isEmpty())
|
||||
args << QLatin1String("--developer-path") << devPath.toString();
|
||||
addDeviceArguments(args);
|
||||
switch (runType) {
|
||||
case IosToolHandler::NormalRun:
|
||||
break;
|
||||
case IosToolHandler::DebugRun:
|
||||
args << QLatin1String("--wait-for-debugger");
|
||||
break;
|
||||
}
|
||||
args << QLatin1String("--args") << extraArgs;
|
||||
op = OpAppRun;
|
||||
start(IosToolHandler::iosSimulatorToolPath(), args);
|
||||
|
||||
Utils::FileName appBundle = Utils::FileName::fromString(bundlePath);
|
||||
if (!appBundle.exists()) {
|
||||
errorMsg(IosToolHandler::tr("Application launch on Simulator failed. Invalid Bundle path %1")
|
||||
.arg(bundlePath));
|
||||
didStartApp(bundlePath, deviceId, Ios::IosToolHandler::Failure);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SimulatorControl::startSimulator(deviceId)) {
|
||||
qint64 pId = -1;
|
||||
bool debugRun = runType == IosToolHandler::DebugRun;
|
||||
QProcess* controlProcess = SimulatorControl::spawnAppProcess(deviceId, appBundle, pId, debugRun, extraArgs);
|
||||
if (controlProcess) {
|
||||
Q_ASSERT(!process || !isRunning());
|
||||
if (process) {
|
||||
delete process;
|
||||
process = nullptr;
|
||||
}
|
||||
process = controlProcess;
|
||||
QObject::connect(process, &QProcess::readyReadStandardOutput,
|
||||
std::bind(&IosSimulatorToolHandlerPrivate::simAppProcessHasData,this));
|
||||
QObject::connect(process, &QProcess::readyReadStandardError,
|
||||
std::bind(&IosSimulatorToolHandlerPrivate::simAppProcessHasErrorOutput,this));
|
||||
QObject::connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
std::bind(&IosSimulatorToolHandlerPrivate::simAppProcessFinished,this, _1,_2));
|
||||
QObject::connect(process, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
|
||||
std::bind(&IosSimulatorToolHandlerPrivate::simAppProcessError, this, _1));
|
||||
|
||||
appPId = pId;
|
||||
gotInferiorPid(bundlePath,deviceId,pId);
|
||||
|
||||
// For debug run, wait for the debugger to attach and then launch the app.
|
||||
if (!debugRun) {
|
||||
launchAppOnSimulator();
|
||||
}
|
||||
} else {
|
||||
errorMsg(IosToolHandler::tr("Spawning the Application process on Simulator failed."));
|
||||
didStartApp(bundlePath, deviceId, Ios::IosToolHandler::Failure);
|
||||
}
|
||||
} else {
|
||||
errorMsg(IosToolHandler::tr("Application launch on Simulator failed. Simulator not running.")
|
||||
.arg(bundlePath));
|
||||
didStartApp(bundlePath, deviceId, Ios::IosToolHandler::Failure);
|
||||
}
|
||||
}
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::launchAppOnSimulator()
|
||||
{
|
||||
// Wait for the app to reach a state when we can launch it on the simulator.
|
||||
if (appPId != -1 && SimulatorControl::waitForProcessSpawn(appPId)) {
|
||||
QByteArray commandOutput;
|
||||
Utils::FileName appBundle = Utils::FileName::fromString(bundlePath);
|
||||
if (SimulatorControl::launchApp(deviceId, SimulatorControl::bundleIdentifier(appBundle), &commandOutput) != -1) {
|
||||
appLaunched = true;
|
||||
didStartApp(bundlePath, deviceId, Ios::IosToolHandler::Success);
|
||||
} else {
|
||||
errorMsg(IosToolHandler::tr("Application launch on Simulator failed. %1")
|
||||
.arg(QString::fromLocal8Bit(commandOutput)));
|
||||
didStartApp(bundlePath, deviceId, Ios::IosToolHandler::Failure);
|
||||
}
|
||||
} else {
|
||||
errorMsg(IosToolHandler::tr("Spawning the Application process on Simulator failed. Spawning timed out."));
|
||||
didStartApp(bundlePath, deviceId, Ios::IosToolHandler::Failure);
|
||||
}
|
||||
}
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::requestDeviceInfo(const QString &deviceId, int timeout)
|
||||
{
|
||||
Q_UNUSED(timeout);
|
||||
this->deviceId = deviceId;
|
||||
QStringList args;
|
||||
args << QLatin1String("showdevicetypes");
|
||||
op = OpDeviceInfo;
|
||||
start(IosToolHandler::iosSimulatorToolPath(), args);
|
||||
Q_UNUSED(deviceId);
|
||||
}
|
||||
|
||||
bool IosSimulatorToolHandlerPrivate::expectsFileDescriptor()
|
||||
void IosSimulatorToolHandlerPrivate::stop(int errorCode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::addDeviceArguments(QStringList &args) const
|
||||
{
|
||||
if (devType.type != IosDeviceType::SimulatedDevice) {
|
||||
qCWarning(toolHandlerLog) << "IosSimulatorToolHandlerPrivate device type is not SimulatedDevice";
|
||||
return;
|
||||
if (process) {
|
||||
if (isRunning()) {
|
||||
process->terminate();
|
||||
if (!process->waitForFinished(1000))
|
||||
process->kill();
|
||||
}
|
||||
args << QLatin1String("--devicetypeid") << devType.identifier;
|
||||
process->deleteLater();
|
||||
process = nullptr;
|
||||
appPId = -1;
|
||||
appLaunched = false;
|
||||
}
|
||||
|
||||
toolExited(errorCode);
|
||||
}
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::debuggerStateChanged(Debugger::DebuggerState state)
|
||||
{
|
||||
if (!appLaunched && state == Debugger::DebuggerState::InferiorRunOk) {
|
||||
// Debugger attached. Launch it on the simulator.
|
||||
launchAppOnSimulator();
|
||||
}
|
||||
}
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::simAppProcessError(QProcess::ProcessError error)
|
||||
{
|
||||
errorMsg(IosToolHandler::tr("Simulator application process error %1").arg(error));
|
||||
}
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::simAppProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
stop((exitStatus == QProcess::NormalExit) ? exitCode : -1 );
|
||||
qCDebug(toolHandlerLog) << "IosToolHandler::finished(" << this << ")";
|
||||
q->finished(q);
|
||||
}
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::simAppProcessHasData()
|
||||
{
|
||||
appOutput(QString::fromLocal8Bit(process->readAllStandardOutput()));
|
||||
}
|
||||
|
||||
void IosSimulatorToolHandlerPrivate::simAppProcessHasErrorOutput()
|
||||
{
|
||||
errorMsg(QString::fromLocal8Bit(process->readAllStandardError()));
|
||||
}
|
||||
|
||||
void IosToolHandlerPrivate::killProcess()
|
||||
@@ -731,18 +858,6 @@ QString IosToolHandler::iosDeviceToolPath()
|
||||
return res;
|
||||
}
|
||||
|
||||
QString IosToolHandler::iosSimulatorToolPath()
|
||||
{
|
||||
Utils::FileName devPath = Internal::IosConfigurations::developerPath();
|
||||
bool version182 = devPath.appendPath(QLatin1String(
|
||||
"Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/iPhoneSimulatorRemoteClient.framework"))
|
||||
.exists();
|
||||
QString res = Core::ICore::libexecPath() + QLatin1String("/ios/iossim");
|
||||
if (version182)
|
||||
res = res.append(QLatin1String("_1_8_2"));
|
||||
return res;
|
||||
}
|
||||
|
||||
IosToolHandler::IosToolHandler(const Internal::IosDeviceType &devType, QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
@@ -762,6 +877,11 @@ void IosToolHandler::stop()
|
||||
d->stop(-1);
|
||||
}
|
||||
|
||||
void IosToolHandler::debuggerStateChanged(int state)
|
||||
{
|
||||
d->debuggerStateChanged((Debugger::DebuggerState)state);
|
||||
}
|
||||
|
||||
void IosToolHandler::requestTransferApp(const QString &bundlePath, const QString &deviceId,
|
||||
int timeout)
|
||||
{
|
||||
@@ -784,24 +904,4 @@ bool IosToolHandler::isRunning()
|
||||
return d->isRunning();
|
||||
}
|
||||
|
||||
void IosToolHandler::subprocessError(QProcess::ProcessError error)
|
||||
{
|
||||
d->subprocessError(error);
|
||||
}
|
||||
|
||||
void IosToolHandler::subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
d->subprocessFinished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void IosToolHandler::subprocessHasData()
|
||||
{
|
||||
d->subprocessHasData();
|
||||
}
|
||||
|
||||
void IosToolHandler::killProcess()
|
||||
{
|
||||
d->killProcess();
|
||||
}
|
||||
|
||||
} // namespace Ios
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <QStringList>
|
||||
#include <QProcess>
|
||||
|
||||
|
||||
namespace Ios {
|
||||
namespace Internal {
|
||||
class IosToolHandlerPrivate;
|
||||
@@ -56,7 +55,6 @@ public:
|
||||
};
|
||||
|
||||
static QString iosDeviceToolPath();
|
||||
static QString iosSimulatorToolPath();
|
||||
|
||||
explicit IosToolHandler(const Internal::IosDeviceType &type, QObject *parent = 0);
|
||||
~IosToolHandler();
|
||||
@@ -66,6 +64,7 @@ public:
|
||||
void requestDeviceInfo(const QString &deviceId, int timeout = 1000);
|
||||
bool isRunning();
|
||||
void stop();
|
||||
void debuggerStateChanged(int state);
|
||||
|
||||
signals:
|
||||
void isTransferringApp(Ios::IosToolHandler *handler, const QString &bundlePath,
|
||||
@@ -85,11 +84,10 @@ signals:
|
||||
void errorMsg(Ios::IosToolHandler *handler, const QString &msg);
|
||||
void toolExited(Ios::IosToolHandler *handler, int code);
|
||||
void finished(Ios::IosToolHandler *handler);
|
||||
private:
|
||||
void subprocessError(QProcess::ProcessError error);
|
||||
void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void subprocessHasData();
|
||||
|
||||
protected:
|
||||
void killProcess();
|
||||
|
||||
private:
|
||||
friend class Ios::Internal::IosToolHandlerPrivate;
|
||||
Ios::Internal::IosToolHandlerPrivate *d;
|
||||
|
||||
422
src/plugins/ios/simulatorcontrol.cpp
Normal file
@@ -0,0 +1,422 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "simulatorcontrol.h"
|
||||
#include "iossimulator.h"
|
||||
#include "iosconfigurations.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMap>
|
||||
#include <QProcess>
|
||||
#include <QReadLocker>
|
||||
#include <QReadWriteLock>
|
||||
#include <QTime>
|
||||
#include <QUrl>
|
||||
#include <QWriteLocker>
|
||||
|
||||
namespace {
|
||||
Q_LOGGING_CATEGORY(simulatorLog, "qtc.ios.simulator")
|
||||
}
|
||||
|
||||
namespace Ios {
|
||||
namespace Internal {
|
||||
|
||||
static int COMMAND_TIMEOUT = 10000;
|
||||
static int SIMULATOR_TIMEOUT = 60000;
|
||||
|
||||
static bool checkForTimeout(const std::chrono::time_point< std::chrono::high_resolution_clock, std::chrono::nanoseconds> &start, int msecs = COMMAND_TIMEOUT)
|
||||
{
|
||||
bool timedOut = false;
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count() > msecs)
|
||||
timedOut = true;
|
||||
return timedOut;
|
||||
}
|
||||
|
||||
class SimulatorControlPrivate :QObject {
|
||||
Q_OBJECT
|
||||
private:
|
||||
struct SimDeviceInfo {
|
||||
bool isBooted() const { return state.compare(QStringLiteral("Booted")) == 0; }
|
||||
bool isAvailable() const { return !availability.contains(QStringLiteral("unavailable")); }
|
||||
QString name;
|
||||
QString udid;
|
||||
QString availability;
|
||||
QString state;
|
||||
QString sdk;
|
||||
};
|
||||
|
||||
SimulatorControlPrivate(QObject *parent = nullptr);
|
||||
~SimulatorControlPrivate();
|
||||
QByteArray runSimCtlCommand(QStringList args) const;
|
||||
SimDeviceInfo deviceInfo(const QString &simUdid) const;
|
||||
bool runCommand(QString command, const QStringList &args, QByteArray *output = nullptr);
|
||||
|
||||
QHash<QString, QProcess*> simulatorProcesses;
|
||||
QReadWriteLock processDataLock;
|
||||
QList<IosDeviceType> availableDevices;
|
||||
QReadWriteLock deviceDataLock;
|
||||
friend class SimulatorControl;
|
||||
};
|
||||
|
||||
SimulatorControlPrivate *SimulatorControl::d = new SimulatorControlPrivate;
|
||||
|
||||
SimulatorControl::SimulatorControl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QList<Ios::Internal::IosDeviceType> SimulatorControl::availableSimulators()
|
||||
{
|
||||
QReadLocker locer(&d->deviceDataLock);
|
||||
return d->availableDevices;
|
||||
}
|
||||
|
||||
void SimulatorControl::updateAvailableSimulators()
|
||||
{
|
||||
const QByteArray output = d->runSimCtlCommand({QLatin1String("list"), QLatin1String("-j"), QLatin1String("devices")});
|
||||
QJsonDocument doc = QJsonDocument::fromJson(output);
|
||||
if (!doc.isNull()) {
|
||||
QList<IosDeviceType> availableDevices;
|
||||
const QJsonObject buildInfo = doc.object().value("devices").toObject();
|
||||
foreach (const QString &buildVersion, buildInfo.keys()) {
|
||||
QJsonArray devices = buildInfo.value(buildVersion).toArray();
|
||||
foreach (const QJsonValue device, devices) {
|
||||
QJsonObject deviceInfo = device.toObject();
|
||||
QString deviceName = QString("%1, %2")
|
||||
.arg(deviceInfo.value("name").toString("Unknown"))
|
||||
.arg(buildVersion);
|
||||
QString deviceUdid = deviceInfo.value("udid").toString("Unknown");
|
||||
if (!deviceInfo.value("availability").toString().contains("unavailable")) {
|
||||
IosDeviceType iOSDevice(IosDeviceType::SimulatedDevice, deviceUdid, deviceName);
|
||||
availableDevices.append(iOSDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::stable_sort(availableDevices.begin(), availableDevices.end());
|
||||
|
||||
{
|
||||
QWriteLocker locker(&d->deviceDataLock);
|
||||
d->availableDevices = availableDevices;
|
||||
}
|
||||
} else {
|
||||
qCDebug(simulatorLog) << "Error parsing json output from simctl. Output:" << output;
|
||||
}
|
||||
}
|
||||
|
||||
// Blocks until simulators reaches "Booted" state.
|
||||
bool SimulatorControl::startSimulator(const QString &simUdid)
|
||||
{
|
||||
QWriteLocker locker(&d->processDataLock);
|
||||
bool simulatorRunning = isSimulatorRunning(simUdid);
|
||||
if (!simulatorRunning && d->deviceInfo(simUdid).isAvailable()) {
|
||||
// Simulator is not running but it's available. Start the simulator.
|
||||
QProcess *p = new QProcess;
|
||||
QObject::connect(p, static_cast<void(QProcess::*)(int)>(&QProcess::finished), [simUdid]() {
|
||||
QWriteLocker locker(&d->processDataLock);
|
||||
d->simulatorProcesses[simUdid]->deleteLater();
|
||||
d->simulatorProcesses.remove(simUdid);
|
||||
});
|
||||
|
||||
const QString cmd = IosConfigurations::developerPath().appendPath(QStringLiteral("/Applications/Simulator.app")).toString();
|
||||
const QStringList args({QStringLiteral("--args"), QStringLiteral("-CurrentDeviceUDID"), simUdid});
|
||||
p->start(cmd, args);
|
||||
|
||||
if (p->waitForStarted()) {
|
||||
d->simulatorProcesses[simUdid] = p;
|
||||
// At this point the sim device exists, available and was not running.
|
||||
// So the simulator is started and we'll wait for it to reach to a state
|
||||
// where we can interact with it.
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
SimulatorControlPrivate::SimDeviceInfo info;
|
||||
do {
|
||||
info = d->deviceInfo(simUdid);
|
||||
} while (!info.isBooted()
|
||||
&& p->state() == QProcess::Running
|
||||
&& !checkForTimeout(start, SIMULATOR_TIMEOUT));
|
||||
simulatorRunning = info.isBooted();
|
||||
} else {
|
||||
qCDebug(simulatorLog) << "Error starting simulator." << p->errorString();
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
return simulatorRunning;
|
||||
}
|
||||
|
||||
bool SimulatorControl::isSimulatorRunning(const QString &simUdid)
|
||||
{
|
||||
if (simUdid.isEmpty())
|
||||
return false;
|
||||
return d->deviceInfo(simUdid).isBooted();
|
||||
}
|
||||
|
||||
bool SimulatorControl::installApp(const QString &simUdid, const Utils::FileName &bundlePath, QByteArray &commandOutput)
|
||||
{
|
||||
bool installed = false;
|
||||
if (isSimulatorRunning(simUdid)) {
|
||||
commandOutput = d->runSimCtlCommand(QStringList() << QStringLiteral("install") << simUdid << bundlePath.toString());
|
||||
installed = commandOutput.isEmpty();
|
||||
} else {
|
||||
commandOutput = "Simulator device not running.";
|
||||
}
|
||||
return installed;
|
||||
}
|
||||
|
||||
qint64 SimulatorControl::launchApp(const QString &simUdid, const QString &bundleIdentifier, QByteArray* commandOutput)
|
||||
{
|
||||
qint64 pId = -1;
|
||||
pId = -1;
|
||||
if (!bundleIdentifier.isEmpty() && isSimulatorRunning(simUdid)) {
|
||||
const QStringList args({QStringLiteral("launch"), simUdid , bundleIdentifier});
|
||||
const QByteArray output = d->runSimCtlCommand(args);
|
||||
const QByteArray pIdStr = output.trimmed().split(' ').last().trimmed();
|
||||
bool validInt = false;
|
||||
pId = pIdStr.toLongLong(&validInt);
|
||||
if (!validInt) {
|
||||
// Launch Failed.
|
||||
qCDebug(simulatorLog) << "Launch app failed. Process id returned is not valid. PID =" << pIdStr;
|
||||
pId = -1;
|
||||
if (commandOutput)
|
||||
*commandOutput = output;
|
||||
}
|
||||
}
|
||||
return pId;
|
||||
}
|
||||
|
||||
QString SimulatorControl::bundleIdentifier(const Utils::FileName &bundlePath)
|
||||
{
|
||||
QString bundleID;
|
||||
#ifdef Q_OS_MAC
|
||||
if (bundlePath.exists()) {
|
||||
CFStringRef cFBundlePath = bundlePath.toString().toCFString();
|
||||
CFURLRef bundle_url = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, cFBundlePath, kCFURLPOSIXPathStyle, true);
|
||||
CFRelease(cFBundlePath);
|
||||
CFBundleRef bundle = CFBundleCreate (kCFAllocatorDefault, bundle_url);
|
||||
CFRelease(bundle_url);
|
||||
CFStringRef cFBundleID = CFBundleGetIdentifier(bundle);
|
||||
bundleID = QString::fromCFString(cFBundleID).trimmed();
|
||||
CFRelease(bundle);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(bundlePath)
|
||||
#endif
|
||||
return bundleID;
|
||||
}
|
||||
|
||||
QString SimulatorControl::bundleExecutable(const Utils::FileName &bundlePath)
|
||||
{
|
||||
QString executable;
|
||||
#ifdef Q_OS_MAC
|
||||
if (bundlePath.exists()) {
|
||||
CFStringRef cFBundlePath = bundlePath.toString().toCFString();
|
||||
CFURLRef bundle_url = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, cFBundlePath, kCFURLPOSIXPathStyle, true);
|
||||
CFRelease(cFBundlePath);
|
||||
CFBundleRef bundle = CFBundleCreate (kCFAllocatorDefault, bundle_url);
|
||||
CFStringRef cFStrExecutableName = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleExecutableKey);
|
||||
executable = QString::fromCFString(cFStrExecutableName).trimmed();
|
||||
CFRelease(bundle);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(bundlePath)
|
||||
#endif
|
||||
return executable;
|
||||
}
|
||||
|
||||
SimulatorControlPrivate::SimulatorControlPrivate(QObject *parent):
|
||||
QObject(parent),
|
||||
processDataLock(QReadWriteLock::Recursive)
|
||||
{
|
||||
}
|
||||
|
||||
SimulatorControlPrivate::~SimulatorControlPrivate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QByteArray SimulatorControlPrivate::runSimCtlCommand(QStringList args) const
|
||||
{
|
||||
QProcess simCtlProcess;
|
||||
args.prepend(QStringLiteral("simctl"));
|
||||
simCtlProcess.start(QStringLiteral("xcrun"), args, QProcess::ReadOnly);
|
||||
if (!simCtlProcess.waitForFinished())
|
||||
qCDebug(simulatorLog) << "simctl command failed." << simCtlProcess.errorString();
|
||||
return simCtlProcess.readAll();
|
||||
}
|
||||
|
||||
// The simctl spawns the process and returns the pId but the application process might not have started, at least in a state where you can interrupt it.
|
||||
// Use SimulatorControl::waitForProcessSpawn to be sure.
|
||||
QProcess *SimulatorControl::spawnAppProcess(const QString &simUdid, const Utils::FileName &bundlePath, qint64 &pId, bool waitForDebugger, const QStringList &extraArgs)
|
||||
{
|
||||
QProcess *simCtlProcess = nullptr;
|
||||
if (isSimulatorRunning(simUdid)) {
|
||||
QString bundleId = bundleIdentifier(bundlePath);
|
||||
QString executableName = bundleExecutable(bundlePath);
|
||||
QByteArray appPath = d->runSimCtlCommand(QStringList() << QStringLiteral("get_app_container") << simUdid << bundleId).trimmed();
|
||||
if (!appPath.isEmpty() && !executableName.isEmpty()) {
|
||||
// Spawn the app. The spawned app is started in suspended mode.
|
||||
appPath.append('/' + executableName.toLocal8Bit());
|
||||
simCtlProcess = new QProcess;
|
||||
QStringList args;
|
||||
args << QStringLiteral("simctl");
|
||||
args << QStringLiteral("spawn");
|
||||
if (waitForDebugger)
|
||||
args << QStringLiteral("-w");
|
||||
args << simUdid;
|
||||
args << QString::fromLocal8Bit(appPath);
|
||||
args << extraArgs;
|
||||
simCtlProcess->start(QStringLiteral("xcrun"), args);
|
||||
if (!simCtlProcess->waitForStarted()){
|
||||
// Spawn command failed.
|
||||
qCDebug(simulatorLog) << "Spawning the app failed." << simCtlProcess->errorString();
|
||||
delete simCtlProcess;
|
||||
simCtlProcess = nullptr;
|
||||
}
|
||||
|
||||
// Find the process id of the the app process.
|
||||
if (simCtlProcess) {
|
||||
qint64 simctlPId = simCtlProcess->processId();
|
||||
pId = -1;
|
||||
QByteArray commandOutput;
|
||||
QStringList pGrepArgs;
|
||||
pGrepArgs << QStringLiteral("-f") << QString::fromLocal8Bit(appPath);
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
// Find the pid of the spawned app.
|
||||
while (pId == -1 && d->runCommand(QStringLiteral("pgrep"), pGrepArgs, &commandOutput)) {
|
||||
foreach (auto pidStr, commandOutput.trimmed().split('\n')) {
|
||||
qint64 parsedPId = pidStr.toLongLong();
|
||||
if (parsedPId != simctlPId)
|
||||
pId = parsedPId;
|
||||
}
|
||||
if (checkForTimeout(begin)) {
|
||||
qCDebug(simulatorLog) << "Spawning the app failed. Process timed out";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pId == -1) {
|
||||
// App process id can't be found.
|
||||
qCDebug(simulatorLog) << "Spawning the app failed. PID not found.";
|
||||
delete simCtlProcess;
|
||||
simCtlProcess = nullptr;
|
||||
}
|
||||
} else {
|
||||
qCDebug(simulatorLog) << "Spawning the app failed. Check installed app." << appPath;
|
||||
}
|
||||
} else {
|
||||
qCDebug(simulatorLog) << "Spawning the app failed. Simulator not running." << simUdid;
|
||||
}
|
||||
return simCtlProcess;
|
||||
}
|
||||
|
||||
bool SimulatorControl::waitForProcessSpawn(qint64 processPId)
|
||||
{
|
||||
bool success = true;
|
||||
if (processPId != -1) {
|
||||
// Wait for app to reach intruptible sleep state.
|
||||
QByteArray wqStr;
|
||||
QStringList args;
|
||||
int wqCount = -1;
|
||||
args << QStringLiteral("-p") << QString::number(processPId) << QStringLiteral("-o") << QStringLiteral("wq=");
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
do {
|
||||
if (!d->runCommand(QStringLiteral("ps"), args, &wqStr)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
bool validInt = false;
|
||||
wqCount = wqStr.toInt(&validInt);
|
||||
if (!validInt) {
|
||||
wqCount = -1;
|
||||
}
|
||||
} while (wqCount < 0 && !checkForTimeout(begin));
|
||||
success = wqCount >= 0;
|
||||
} else {
|
||||
qCDebug(simulatorLog) << "Wait for spawned failed. Invalid Process ID." << processPId;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
SimulatorControlPrivate::SimDeviceInfo SimulatorControlPrivate::deviceInfo(const QString &simUdid) const
|
||||
{
|
||||
SimDeviceInfo info;
|
||||
bool found = false;
|
||||
if (!simUdid.isEmpty()) {
|
||||
// It might happend that the simulator is not started by SimControl.
|
||||
// Check of intances started externally.
|
||||
const QByteArray output = runSimCtlCommand({QLatin1String("list"), QLatin1String("-j"), QLatin1String("devices")});
|
||||
QJsonDocument doc = QJsonDocument::fromJson(output);
|
||||
if (!doc.isNull()) {
|
||||
const QJsonObject buildInfo = doc.object().value(QStringLiteral("devices")).toObject();
|
||||
foreach (const QString &buildVersion, buildInfo.keys()) {
|
||||
QJsonArray devices = buildInfo.value(buildVersion).toArray();
|
||||
foreach (const QJsonValue device, devices) {
|
||||
QJsonObject deviceInfo = device.toObject();
|
||||
QString deviceUdid = deviceInfo.value(QStringLiteral("udid")).toString();
|
||||
if (deviceUdid.compare(simUdid) == 0) {
|
||||
found = true;
|
||||
info.name = deviceInfo.value(QStringLiteral("name")).toString();
|
||||
info.udid = deviceUdid;
|
||||
info.state = deviceInfo.value(QStringLiteral("state")).toString();
|
||||
info.sdk = buildVersion;
|
||||
info.availability = deviceInfo.value(QStringLiteral("availability")).toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
qCDebug(simulatorLog) << "Cannot find device info. Error parsing json output from simctl. Output:" << output;
|
||||
}
|
||||
} else {
|
||||
qCDebug(simulatorLog) << "Cannot find device info. Invalid UDID.";
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
bool SimulatorControlPrivate::runCommand(QString command, const QStringList &args, QByteArray *output)
|
||||
{
|
||||
bool success = false;
|
||||
QProcess process;
|
||||
process.start(command, args);
|
||||
success = process.waitForFinished();
|
||||
if (output)
|
||||
*output = process.readAll().trimmed();
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Ios
|
||||
#include "simulatorcontrol.moc"
|
||||
64
src/plugins/ios/simulatorcontrol.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#ifndef SIMULATORCONTROL_H
|
||||
#define SIMULATORCONTROL_H
|
||||
|
||||
#include <QHash>
|
||||
#include "utils/fileutils.h"
|
||||
|
||||
class QProcess;
|
||||
|
||||
namespace Ios {
|
||||
namespace Internal {
|
||||
|
||||
class IosDeviceType;
|
||||
class SimulatorControlPrivate;
|
||||
|
||||
class SimulatorControl
|
||||
{
|
||||
explicit SimulatorControl();
|
||||
|
||||
public:
|
||||
static QList<IosDeviceType> availableSimulators();
|
||||
static void updateAvailableSimulators();
|
||||
|
||||
static bool startSimulator(const QString &simUdid);
|
||||
static bool isSimulatorRunning(const QString &simUdid);
|
||||
|
||||
static bool installApp(const QString &simUdid, const Utils::FileName &bundlePath, QByteArray &commandOutput);
|
||||
static QProcess* spawnAppProcess(const QString &simUdid, const Utils::FileName &bundlePath, qint64 &pId,
|
||||
bool waitForDebugger, const QStringList &extraArgs);
|
||||
|
||||
static qint64 launchApp(const QString &simUdid, const QString &bundleIdentifier, QByteArray *commandOutput = nullptr);
|
||||
static QString bundleIdentifier(const Utils::FileName &bundlePath);
|
||||
static QString bundleExecutable(const Utils::FileName &bundlePath);
|
||||
static bool waitForProcessSpawn(qint64 processPId);
|
||||
|
||||
private:
|
||||
static SimulatorControlPrivate *d;
|
||||
};
|
||||
} // namespace Internal
|
||||
} // namespace Ios
|
||||
#endif // SIMULATORCONTROL_H
|
||||
@@ -77,7 +77,7 @@ exists(../shared/qbs/qbs.pro)|!isEmpty(QBS_INSTALL_DIR): \
|
||||
isEmpty(LLVM_INSTALL_DIR):LLVM_INSTALL_DIR=$$(LLVM_INSTALL_DIR)
|
||||
exists($$LLVM_INSTALL_DIR) {
|
||||
SUBDIRS += clangcodemodel
|
||||
SUBDIRS += clangrefactoring
|
||||
# SUBDIRS += clangrefactoring
|
||||
} else {
|
||||
warning("Set LLVM_INSTALL_DIR to build the Clang Code Model. " \
|
||||
"For details, see doc/src/editors/creator-clang-codemodel.qdoc.")
|
||||
|
||||
@@ -208,7 +208,16 @@ Utils::FileName AbstractMsvcToolChain::compilerCommand() const
|
||||
{
|
||||
Utils::Environment env = Utils::Environment::systemEnvironment();
|
||||
addToEnvironment(env);
|
||||
return env.searchInPath(QLatin1String("cl.exe"));
|
||||
|
||||
Utils::FileName clexe = env.searchInPath(QLatin1String("cl.exe"), QStringList(), [](const QString &name) {
|
||||
QDir dir(QDir::cleanPath(QFileInfo(name).absolutePath() + QStringLiteral("/..")));
|
||||
do {
|
||||
if (QFile::exists(dir.absoluteFilePath(QStringLiteral("vcvarsall.bat"))))
|
||||
return true;
|
||||
} while (dir.cdUp() && !dir.isRoot());
|
||||
return false;
|
||||
});
|
||||
return clexe;
|
||||
}
|
||||
|
||||
IOutputParser *AbstractMsvcToolChain::outputParser() const
|
||||
|
||||
@@ -1061,6 +1061,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
|
||||
|
||||
connect(ICore::instance(), &ICore::saveSettingsRequested,
|
||||
dd, &ProjectExplorerPluginPrivate::savePersistentSettings);
|
||||
connect(EditorManager::instance(), &EditorManager::autoSaved, this, [this] {
|
||||
if (!dd->m_shuttingDown && !SessionManager::loadingSession())
|
||||
SessionManager::save();
|
||||
});
|
||||
|
||||
addAutoReleasedObject(new ProjectTreeWidgetFactory);
|
||||
addAutoReleasedObject(new FolderNavigationWidgetFactory);
|
||||
@@ -1518,11 +1522,7 @@ void ProjectExplorerPlugin::openNewProjectDialog()
|
||||
|
||||
void ProjectExplorerPluginPrivate::showSessionManager()
|
||||
{
|
||||
if (SessionManager::isDefaultVirgin()) {
|
||||
// do not save new virgin default sessions
|
||||
} else {
|
||||
SessionManager::save();
|
||||
}
|
||||
SessionDialog sessionDialog(ICore::mainWindow());
|
||||
sessionDialog.setAutoLoadSession(dd->m_projectExplorerSettings.autorestoreLastSession);
|
||||
sessionDialog.exec();
|
||||
@@ -1551,12 +1551,8 @@ void ProjectExplorerPluginPrivate::savePersistentSettings()
|
||||
foreach (Project *pro, SessionManager::projects())
|
||||
pro->saveSettings();
|
||||
|
||||
if (SessionManager::isDefaultVirgin()) {
|
||||
// do not save new virgin default sessions
|
||||
} else {
|
||||
SessionManager::save();
|
||||
}
|
||||
}
|
||||
|
||||
QSettings *s = ICore::settings();
|
||||
s->setValue(QLatin1String("ProjectExplorer/StartupSession"), SessionManager::activeSession());
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <QComboBox>
|
||||
#include <QDockWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QTimer>
|
||||
@@ -234,6 +235,11 @@ public:
|
||||
{
|
||||
Q_UNUSED(column)
|
||||
|
||||
if (role == ItemUpdatedFromBelowRole) {
|
||||
announceChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (role == ItemDeactivatedFromBelowRole) {
|
||||
announceChange();
|
||||
return true;
|
||||
@@ -375,16 +381,13 @@ public:
|
||||
this, &SelectorModel::openContextMenu);
|
||||
}
|
||||
|
||||
void announceChange()
|
||||
{
|
||||
m_changeListener(m_projectsModel.rootItem()->childAt(0)->data(0, PanelWidgetRole).value<QWidget *>());
|
||||
}
|
||||
|
||||
void updatePanel()
|
||||
{
|
||||
announceChange();
|
||||
ProjectItem *projectItem = m_projectsModel.rootItem()->childAt(0);
|
||||
m_changeListener(projectItem->data(0, PanelWidgetRole).value<QWidget *>());
|
||||
|
||||
QModelIndex activeIndex = m_projectsModel.rootItem()->childAt(0)->activeIndex();
|
||||
QModelIndex activeIndex = projectItem->activeIndex();
|
||||
m_selectorTree->expandAll();
|
||||
m_selectorTree->selectionModel()->clear();
|
||||
m_selectorTree->selectionModel()->select(activeIndex, QItemSelectionModel::Select);
|
||||
}
|
||||
@@ -481,9 +484,16 @@ ProjectWindow::ProjectWindow()
|
||||
selectorView->setWindowTitle(tr("Project Selector"));
|
||||
selectorView->setAutoFillBackground(true);
|
||||
|
||||
auto activeLabel = new QLabel(tr("Active Project"));
|
||||
QFont font = activeLabel->font();
|
||||
font.setBold(true);
|
||||
font.setPointSizeF(font.pointSizeF() * 1.2);
|
||||
activeLabel->setFont(font);
|
||||
|
||||
auto innerLayout = new QVBoxLayout;
|
||||
innerLayout->setSpacing(10);
|
||||
innerLayout->setContentsMargins(14, innerLayout->spacing(), 14, 0);
|
||||
innerLayout->addWidget(activeLabel);
|
||||
innerLayout->addWidget(selectorModel->m_projectSelection);
|
||||
innerLayout->addWidget(selectorModel->m_selectorTree);
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ enum {
|
||||
ItemActivatedFromBelowRole, // A subitem gots activated and gives us the opportunity to adjust
|
||||
ItemActivatedFromAboveRole, // A parent item gots activated and makes us its active child.
|
||||
ItemDeactivatedFromBelowRole, // A subitem got deactivated and gives us the opportunity to adjust
|
||||
ItemUpdatedFromBelowRole, // A subitem got updated, re-expansion is necessary.
|
||||
ActiveItemRole, // The index of the currently selected item in the tree view
|
||||
PanelWidgetRole // This item's widget to be shown as central widget.
|
||||
};
|
||||
|
||||
@@ -408,6 +408,10 @@ bool SessionManager::loadingSession()
|
||||
|
||||
bool SessionManager::save()
|
||||
{
|
||||
// do not save new virgin default sessions
|
||||
if (isDefaultVirgin())
|
||||
return true;
|
||||
|
||||
emit m_instance->aboutToSaveSession();
|
||||
|
||||
if (!d->m_writer || d->m_writer->fileName() != sessionNameToFileName(d->m_sessionName)) {
|
||||
@@ -961,12 +965,10 @@ bool SessionManager::loadSession(const QString &session)
|
||||
// Allow everyone to set something in the session and before saving
|
||||
emit m_instance->aboutToUnloadSession(d->m_sessionName);
|
||||
|
||||
if (!isDefaultVirgin()) {
|
||||
if (!save()) {
|
||||
d->m_loadingSession = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
if (!EditorManager::closeAllEditors()) {
|
||||
|
||||
@@ -212,6 +212,7 @@ public:
|
||||
|
||||
void handleRemovedKit(Kit *kit);
|
||||
void handleAddedKit(Kit *kit);
|
||||
void handleUpdatedKit(Kit *kit);
|
||||
|
||||
void handleTargetAdded(Target *target);
|
||||
void handleTargetRemoved(Target *target);
|
||||
@@ -755,6 +756,8 @@ TargetGroupItemPrivate::TargetGroupItemPrivate(TargetGroupItem *q, Project *proj
|
||||
this, &TargetGroupItemPrivate::handleAddedKit);
|
||||
connect(KitManager::instance(), &KitManager::kitRemoved,
|
||||
this, &TargetGroupItemPrivate::handleRemovedKit);
|
||||
connect(KitManager::instance(), &KitManager::kitUpdated,
|
||||
this, &TargetGroupItemPrivate::handleUpdatedKit);
|
||||
|
||||
rebuildContents();
|
||||
}
|
||||
@@ -789,7 +792,7 @@ QVariant TargetGroupItem::data(int column, int role) const
|
||||
bool TargetGroupItem::setData(int column, const QVariant &data, int role)
|
||||
{
|
||||
Q_UNUSED(data)
|
||||
if (role == ItemActivatedFromBelowRole) {
|
||||
if (role == ItemActivatedFromBelowRole || role == ItemUpdatedFromBelowRole) {
|
||||
// Bubble up to trigger setting the active project.
|
||||
parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), role);
|
||||
return true;
|
||||
@@ -823,8 +826,15 @@ void TargetGroupItemPrivate::handleRemovedKit(Kit *kit)
|
||||
rebuildContents();
|
||||
}
|
||||
|
||||
void TargetGroupItemPrivate::handleUpdatedKit(Kit *kit)
|
||||
{
|
||||
Q_UNUSED(kit);
|
||||
rebuildContents();
|
||||
}
|
||||
|
||||
void TargetGroupItemPrivate::handleAddedKit(Kit *kit)
|
||||
{
|
||||
if (m_project->supportsKit(kit))
|
||||
q->appendChild(new TargetItem(m_project, kit->id()));
|
||||
}
|
||||
|
||||
@@ -843,8 +853,14 @@ void TargetGroupItemPrivate::rebuildContents()
|
||||
{
|
||||
q->removeChildren();
|
||||
|
||||
foreach (Kit *kit, KitManager::sortKits(KitManager::kits()))
|
||||
KitMatcher matcher([this](const Kit *kit) { return m_project->supportsKit(const_cast<Kit *>(kit)); });
|
||||
const QList<Kit *> kits = KitManager::sortKits(KitManager::matchingKits(matcher));
|
||||
for (Kit *kit : kits)
|
||||
q->appendChild(new TargetItem(m_project, kit->id()));
|
||||
|
||||
if (q->parent())
|
||||
q->parent()->setData(0, QVariant::fromValue(static_cast<TreeItem *>(q)),
|
||||
ItemUpdatedFromBelowRole);
|
||||
}
|
||||
|
||||
void TargetGroupItemPrivate::handleTargetAdded(Target *target)
|
||||
|
||||
@@ -1477,7 +1477,9 @@ void QmakeProject::collectLibraryData(const QmakeProFileNode *node, DeploymentDa
|
||||
destDir.append(QLatin1Char('/')).append(ti.target)
|
||||
.append(QLatin1String(".framework"));
|
||||
} else {
|
||||
if (!(isPlugin && config.contains(QLatin1String("no_plugin_name_prefix"))))
|
||||
targetFileName.prepend(QLatin1String("lib"));
|
||||
|
||||
if (!isPlugin) {
|
||||
targetFileName += QLatin1Char('.');
|
||||
const QString version = node->singleVariableValue(VersionVar);
|
||||
@@ -1496,7 +1498,9 @@ void QmakeProject::collectLibraryData(const QmakeProFileNode *node, DeploymentDa
|
||||
case Abi::LinuxOS:
|
||||
case Abi::BsdOS:
|
||||
case Abi::UnixOS:
|
||||
if (!(isPlugin && config.contains(QLatin1String("no_plugin_name_prefix"))))
|
||||
targetFileName.prepend(QLatin1String("lib"));
|
||||
|
||||
targetFileName += QLatin1Char('.');
|
||||
if (isStatic) {
|
||||
targetFileName += QLatin1Char('a');
|
||||
|
||||
@@ -63,7 +63,7 @@ static CrumbleBarInfo createCrumbleBarInfoFromModelNode(const ModelNode &modelNo
|
||||
{
|
||||
CrumbleBarInfo crumbleBarInfo;
|
||||
crumbleBarInfo.displayName = componentIdForModelNode(modelNode);
|
||||
crumbleBarInfo.fileName = currentDesignDocument()->textEditor()->document()->filePath().toString();
|
||||
crumbleBarInfo.fileName = currentDesignDocument()->textEditor()->document()->filePath();
|
||||
crumbleBarInfo.modelNode = modelNode;
|
||||
|
||||
return crumbleBarInfo;
|
||||
@@ -87,7 +87,7 @@ CrumbleBar::~CrumbleBar()
|
||||
delete m_crumblePath;
|
||||
}
|
||||
|
||||
void CrumbleBar::pushFile(const QString &fileName)
|
||||
void CrumbleBar::pushFile(const Utils::FileName &fileName)
|
||||
{
|
||||
if (m_isInternalCalled == false) {
|
||||
crumblePath()->clear();
|
||||
@@ -102,7 +102,7 @@ void CrumbleBar::pushFile(const QString &fileName)
|
||||
CrumbleBarInfo crumbleBarInfo;
|
||||
crumbleBarInfo.fileName = fileName;
|
||||
|
||||
crumblePath()->pushElement(fileName.split(QLatin1String("/")).last(), QVariant::fromValue(crumbleBarInfo));
|
||||
crumblePath()->pushElement(fileName.fileName(), QVariant::fromValue(crumbleBarInfo));
|
||||
|
||||
m_isInternalCalled = false;
|
||||
|
||||
@@ -171,7 +171,7 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data)
|
||||
|
||||
m_isInternalCalled = true;
|
||||
if (!clickedCrumbleBarInfo.modelNode.isValid()
|
||||
&& Utils::FileName::fromString(clickedCrumbleBarInfo.fileName) == currentDesignDocument()->fileName()) {
|
||||
&& clickedCrumbleBarInfo.fileName == currentDesignDocument()->fileName()) {
|
||||
nextFileIsCalledInternally();
|
||||
currentDesignDocument()->changeToDocumentModel();
|
||||
QmlDesignerPlugin::instance()->viewManager().setComponentViewToMaster();
|
||||
@@ -179,8 +179,8 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data)
|
||||
showSaveDialog();
|
||||
crumblePath()->popElement();
|
||||
nextFileIsCalledInternally();
|
||||
Core::EditorManager::openEditor(clickedCrumbleBarInfo.fileName, Core::Id(),
|
||||
Core::EditorManager::DoNotMakeVisible);
|
||||
Core::EditorManager::openEditor(clickedCrumbleBarInfo.fileName.toString(),
|
||||
Core::Id(), Core::EditorManager::DoNotMakeVisible);
|
||||
if (clickedCrumbleBarInfo.modelNode.isValid()) {
|
||||
currentDesignDocument()->changeToSubComponent(clickedCrumbleBarInfo.modelNode);
|
||||
QmlDesignerPlugin::instance()->viewManager().setComponentNode(clickedCrumbleBarInfo.modelNode);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <utils/crumblepath.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <modelnode.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
@@ -38,7 +39,7 @@ public:
|
||||
explicit CrumbleBar(QObject *parent = 0);
|
||||
~CrumbleBar();
|
||||
|
||||
void pushFile(const QString &fileName);
|
||||
void pushFile(const Utils::FileName &fileName);
|
||||
void pushInFileComponent(const ModelNode &modelNode);
|
||||
|
||||
void nextFileIsCalledInternally();
|
||||
@@ -59,7 +60,7 @@ private:
|
||||
|
||||
class CrumbleBarInfo {
|
||||
public:
|
||||
QString fileName;
|
||||
Utils::FileName fileName;
|
||||
QString displayName;
|
||||
ModelNode modelNode;
|
||||
};
|
||||
|
||||
@@ -71,10 +71,10 @@ static bool importLess(const Import &firstImport, const Import &secondImport)
|
||||
return false;
|
||||
|
||||
if (firstImport.isLibraryImport() && secondImport.isFileImport())
|
||||
return true;
|
||||
return false;
|
||||
|
||||
if (firstImport.isFileImport() && secondImport.isLibraryImport())
|
||||
return false;
|
||||
return true;
|
||||
|
||||
if (firstImport.isFileImport() && secondImport.isFileImport())
|
||||
return QString::localeAwareCompare(firstImport.file(), secondImport.file()) < 0;
|
||||
|
||||
@@ -191,7 +191,9 @@ void ComponentView::searchForComponentAndAddToList(const ModelNode &node)
|
||||
bool masterNotAdded = true;
|
||||
|
||||
foreach (const ModelNode &node, node.allSubModelNodesAndThisNode()) {
|
||||
if (node.nodeSourceType() == ModelNode::NodeWithComponentSource) {
|
||||
if (node.nodeSourceType() == ModelNode::NodeWithComponentSource
|
||||
|| (node.hasParentProperty()
|
||||
&& !node.parentProperty().isDefaultProperty())) {
|
||||
if (masterNotAdded) {
|
||||
masterNotAdded = true;
|
||||
addMasterDocument();
|
||||
@@ -200,9 +202,6 @@ void ComponentView::searchForComponentAndAddToList(const ModelNode &node)
|
||||
if (!hasEntryForNode(node)) {
|
||||
QString description = descriptionForNode(node);
|
||||
|
||||
|
||||
|
||||
|
||||
QStandardItem *item = new QStandardItem(description);
|
||||
item->setData(QVariant::fromValue(node.internalId()), ModelNodeRole);
|
||||
item->setEditable(false);
|
||||
|
||||
@@ -321,7 +321,7 @@ void DesignDocument::changeToMaster()
|
||||
if (m_inFileComponentModel)
|
||||
changeToDocumentModel();
|
||||
|
||||
QmlDesignerPlugin::instance()->viewManager().pushFileOnCrumbleBar(fileName().toString());
|
||||
QmlDesignerPlugin::instance()->viewManager().pushFileOnCrumbleBar(fileName());
|
||||
QmlDesignerPlugin::instance()->viewManager().setComponentNode(rootModelNode());
|
||||
}
|
||||
|
||||
|
||||