Merge remote-tracking branch 'origin/4.2'

Change-Id: I3a54f679238e6eb4f053608286fc39eae3041561
This commit is contained in:
Eike Ziller
2016-10-17 16:22:04 +02:00
157 changed files with 4676 additions and 5430 deletions

View File

@@ -19,6 +19,9 @@ Prerequisites:
* ActiveState Active Perl * ActiveState Active Perl
* MinGW with g++ 4.8 or Visual Studio 2015 or later * MinGW with g++ 4.8 or Visual Studio 2015 or later
* jom * jom
The optional Clang code model requires LLVM. A manual build of it requires in addition:
* cmake
* On Mac OS X: latest Xcode * On Mac OS X: latest Xcode
* On Linux: g++ 4.8 or later * On Linux: g++ 4.8 or later
* LLVM 3.8.0 or later (optional, needed for the Clang Code Model) * 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. command...` error. If a `sh.exe` is found, the compile process will fail.
You have to remove it from the path. You have to remove it from the path.
10. To enable the Clang-based code model: Install Clang (>= version 3.8.0) 10. As of Qt Creator 4.2, a complete build of LLVM and Clang is required
and set the environment variable LLVM_INSTALL_DIR to point to the 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. 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. 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 Please see <https://wiki.qt.io/Building_Qt_5_from_Git> for

72
dist/changes-4.1.1.md vendored Normal file
View 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)

View File

@@ -38,12 +38,14 @@
\title Specifying Build Settings \title Specifying Build Settings
Different build configurations allow you to quickly switch between Different build configurations allow you to quickly switch between
different build settings. By default, \QC creates \b debug different build settings. By default, \QC creates \e debug, \e release, and
and \b release build configurations. A debug build contains additional \e profile build configurations. A debug build contains additional
debug symbols that you need for debugging the application but that you debug symbols that you need for debugging the application but that you
can leave out from the release version. Generally, you use the debug can leave out from the release version. Generally, you use the debug
configuration for testing and the release configuration for creating 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. You specify build settings in the \uicontrol Projects mode.
To add a new build configuration, click \uicontrol Add and select the type of To add a new build configuration, click \uicontrol Add and select the type of

111
scripts/createSourcePackages.py Executable file
View 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()

View File

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

View File

@@ -196,3 +196,9 @@ class Dumper(DumperBase):
def nativeDynamicTypeName(self, address, baseType): def nativeDynamicTypeName(self, address, baseType):
return None # FIXME: Seems sufficient, no idea why. 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

View File

@@ -2999,6 +2999,8 @@ class DumperBase:
return self.code in (TypeCodeIntegral, TypeCodeFloat, TypeCodeEnum) return self.code in (TypeCodeIntegral, TypeCodeFloat, TypeCodeEnum)
def alignment(self): def alignment(self):
if self.code == TypeCodeTypedef:
return self.stripTypedefs().alignment()
if self.isSimpleType(): if self.isSimpleType():
if self.name == 'double': if self.name == 'double':
return self.dumper.ptrSize() # Crude approximation. return self.dumper.ptrSize() # Crude approximation.
@@ -3371,7 +3373,9 @@ class DumperBase:
builder.addField(ptrSize, 'Q' if ptrSize == 8 else 'I') builder.addField(ptrSize, 'Q' if ptrSize == 8 else 'I')
elif c == 'P': # Pointer as Value elif c == 'P': # Pointer as Value
builder.addField(ptrSize, '%ss' % ptrSize) 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) builder.addField(8, c)
elif c in ('i', 'I', 'f'): elif c in ('i', 'I', 'f'):
builder.addField(4, c) builder.addField(4, c)

View File

@@ -353,6 +353,7 @@ def qdump__QDateTime(d, value):
def qdump__QDir(d, value): def qdump__QDir(d, value):
if not d.isMsvcTarget():
d.putNumChild(1) d.putNumChild(1)
privAddress = d.extractPointer(value) privAddress = d.extractPointer(value)
bit32 = d.ptrSize() == 4 bit32 = d.ptrSize() == 4
@@ -424,7 +425,7 @@ def qdump__QDir(d, value):
absoluteDirEntryOffset = dirEntryOffset + fileSystemEntrySize absoluteDirEntryOffset = dirEntryOffset + fileSystemEntrySize
d.putStringValue(privAddress + dirEntryOffset) d.putStringValue(privAddress + dirEntryOffset)
if d.isExpanded(): if d.isExpanded() and not d.isMsvcTarget():
with Children(d): with Children(d):
ns = d.qtNamespace() ns = d.qtNamespace()
d.call('int', value, 'count') # Fill cache. d.call('int', value, 'count') # Fill cache.
@@ -1042,7 +1043,7 @@ def qdump__QPixmap(d, value):
else: else:
(dummy, width, height) = d.split('pii', dataPtr) (dummy, width, height) = d.split('pii', dataPtr)
d.putValue('(%dx%d)' % (width, height)) d.putValue('(%dx%d)' % (width, height))
d.putNumChild(0) d.putPlainChildren(value)
def qdump__QPoint(d, value): def qdump__QPoint(d, value):

View File

@@ -213,12 +213,20 @@ def qform__std__map():
def qdump__std__map(d, value): def qdump__std__map(d, value):
if d.isQnxTarget(): 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 return
# stuff is actually (color, pad) with 'I@', but we can save cycles/ # stuff is actually (color, pad) with 'I@', but we can save cycles/
(compare, stuff, parent, left, right, size) = value.split('pppppp') (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.check(0 <= size and size <= 100*1000*1000)
d.putItemCount(size) d.putItemCount(size)
@@ -226,7 +234,7 @@ def qdump__std__map(d, value):
pairType = value.type[3][0] pairType = value.type[3][0]
pairPointer = pairType.pointer() pairPointer = pairType.pointer()
with PairedChildren(d, size, pairType=pairType, maxNumChild=1000): 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() nodeSize = node.dereference().type.size()
typeCode = "@{%s}@{%s}" % (pairType[0].name, pairType[1].name) typeCode = "@{%s}@{%s}" % (pairType[0].name, pairType[1].name)
for i in d.childRange(): for i in d.childRange():
@@ -248,26 +256,23 @@ def qdump__std__map(d, value):
break break
node = node["_M_left"] node = node["_M_left"]
def qdump__std__map__QNX(d, value): def qdump_std__map__helper(d, size, value):
size = value['_Mysize']
d.check(0 <= size and size <= 100*1000*1000)
d.putItemCount(size)
if d.isExpanded(): if d.isExpanded():
head = value['_Myhead'] head = value['_Myhead']
node = head['_Left'] node = head['_Left']
nodeType = head.type 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(): for i in d.childRange():
pair = node.cast(nodeType).dereference()['_Myval'] pair = node.cast(nodeType).dereference()['_Myval']
d.putPairItem(i, pair) d.putPairItem(i, pair)
if not node['_Right']['_Isnil']: if node['_Right']['_Isnil'].integer() == 0:
node = node['_Right'] node = node['_Right']
while not node['_Left']['_Isnil']: while node['_Left']['_Isnil'].integer() == 0:
node = node['_Left'] node = node['_Left']
else: else:
parent = node['_Parent'] parent = node['_Parent']
while node == parent['_Right']['_Isnil']: while node and parent['_Right']['_Isnil'].integer() == 0:
node = parent node = parent
parent = parent['_Parent'] parent = parent['_Parent']
if node['_Right'] != parent: if node['_Right'] != parent:
@@ -794,7 +799,7 @@ def qedit__std__vector(d, value, data):
gdb.execute(cmd) gdb.execute(cmd)
def qdump__std__vector(d, value): def qdump__std__vector(d, value):
if d.isQnxTarget(): if d.isQnxTarget() or d.isMsvcTarget():
qdumpHelper__std__vector__QNX(d, value) qdumpHelper__std__vector__QNX(d, value)
else: else:
qdumpHelper__std__vector(d, value, False) qdumpHelper__std__vector(d, value, False)
@@ -835,20 +840,26 @@ def qdumpHelper__std__vector(d, value, isLibCpp):
def qdumpHelper__std__vector__QNX(d, value): def qdumpHelper__std__vector__QNX(d, value):
innerType = value.type[0] innerType = value.type[0]
isBool = str(innerType) == 'bool' isBool = innerType.name == 'bool'
if isBool: if isBool:
try:
impl = value['_Myvec']['_Mypair']['_Myval2']
except:
impl = value['_Myvec'] impl = value['_Myvec']
start = impl['_Myfirst'] start = impl['_Myfirst'].pointer()
last = impl['_Mylast'] last = impl['_Mylast'].pointer()
end = impl['_Myend'] end = impl['_Myend'].pointer()
size = value['_Mysize'] size = value['_Mysize'].integer()
storagesize = start.dereference().type.size() * 8 storagesize = start.dereference().type.size() * 8
else: else:
start = value['_Myfirst'] try:
last = value['_Mylast'] impl = value['_Mypair']['_Myval2']
end = value['_Myend'] except:
size = (last.integer() - start.integer()) / innerType.size() impl = value
alloc = (end.integer() - start.integer()) / innerType.size() 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(0 <= size and size <= 1000 * 1000 * 1000)
d.check(last <= end) d.check(last <= end)
@@ -863,11 +874,11 @@ def qdumpHelper__std__vector__QNX(d, value):
for i in d.childRange(): for i in d.childRange():
q = start + int(i / storagesize) q = start + int(i / storagesize)
with SubItem(d, i): with SubItem(d, i):
d.putValue((q.dereference() >> (i % storagesize)) & 1) d.putValue((q.dereference().pointer() >> (i % storagesize)) & 1)
d.putType("bool") d.putType("bool")
d.putNumChild(0) d.putNumChild(0)
else: else:
d.putArrayData(start, size, innerType) d.putPlotData(start, size, innerType)
def qdump__std____1__vector(d, value): def qdump__std____1__vector(d, value):
qdumpHelper__std__vector(d, value, True) qdumpHelper__std__vector(d, value, True)

View File

@@ -336,6 +336,10 @@ void ObjectNodeInstance::addToNewProperty(QObject *object, QObject *newParent, c
list.append(object); list.append(object);
} else if (isObject(property)) { } else if (isObject(property)) {
property.write(objectToVariant(object)); 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()); Q_ASSERT(objectToVariant(object).isValid());

View File

@@ -190,8 +190,9 @@ Column {
ButtonRowButton { ButtonRowButton {
iconSource: "images/icon_color_solid.png" iconSource: "images/icon_color_solid.png"
onClicked: { onClicked: {
colorEditor.backendValue.resetValue()
gradientLine.deleteGradient() gradientLine.deleteGradient()
textField.text = colorEditor.color
colorEditor.backendValue.resetValue()
} }
tooltip: qsTr("Solid Color") tooltip: qsTr("Solid Color")
} }

View File

@@ -33,6 +33,8 @@ ComboBoxStyle {
} }
padding.left: 20
background: Item { background: Item {
implicitWidth: 120 implicitWidth: 120
implicitHeight: 24 implicitHeight: 24
@@ -65,18 +67,14 @@ ComboBoxStyle {
} }
} }
label: Item { label: Text {
implicitWidth: textitem.implicitWidth + 20
Text {
id: textitem id: textitem
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: control.currentText text: control.currentText
renderType: Text.NativeRendering renderType: Text.NativeRendering
color: control.textColor color: control.textColor
} }
}
__dropDownStyle: MenuStyle { __dropDownStyle: MenuStyle {
__maxPopupHeight: 600 __maxPopupHeight: 600

View File

@@ -133,6 +133,8 @@ Controls.TextField {
event.accepted = true event.accepted = true
if (textField.completionActive) { if (textField.completionActive) {
listView.model = null listView.model = null
} else {
textField.rejected()
} }
} }

View File

@@ -40,7 +40,7 @@ Controls.ComboBox {
model: ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] model: ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"]
onModelChanged: { onModelChanged: {
editText = backendValue.valueToString editText = comboBox.backendValue.valueToString
} }
style: CustomComboBoxStyle { style: CustomComboBoxStyle {
@@ -50,7 +50,7 @@ Controls.ComboBox {
ColorLogic { ColorLogic {
id: colorLogic id: colorLogic
backendValue: comboBox.backendValue backendValue: comboBox.backendValue
property string textValue: backendValue.value property string textValue: comboBox.backendValue.valueToString
onTextValueChanged: { onTextValueChanged: {
comboBox.editText = textValue comboBox.editText = textValue
} }

View File

@@ -60,7 +60,7 @@ Section {
text: qsTr("Font") text: qsTr("Font")
} }
FontComboBox { FontComboBox {
backendValue: fontFamily backendValue: fontSection.fontFamily
Layout.fillWidth: true 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 { Label {
visible: showStyle visible: showStyle
text: qsTr("Style") text: qsTr("Style")
@@ -154,5 +178,41 @@ Section {
model: ["Normal", "Outline", "Raised", "Sunken"] model: ["Normal", "Outline", "Raised", "Sunken"]
scope: "Text" 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
}
}
} }
} }

View File

@@ -108,7 +108,7 @@ Controls.TextField {
selectionColor: creatorTheme.PanelTextColorLight selectionColor: creatorTheme.PanelTextColorLight
selectedTextColor: creatorTheme.PanelTextColorMid selectedTextColor: creatorTheme.PanelTextColorMid
textColor: creatorTheme.PanelTextColorLight textColor: lineEdit.textColor
placeholderTextColor: creatorTheme.PanelTextColorMid placeholderTextColor: creatorTheme.PanelTextColorMid
padding.top: 3 padding.top: 3

View File

@@ -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
}
}
}
}

View File

@@ -33,9 +33,11 @@ Section {
caption: qsTr("Text") caption: qsTr("Text")
property bool showIsWrapping: false property bool showIsWrapping: false
property bool showElide: false
property bool showVerticalAlignment: false property bool showVerticalAlignment: false
property bool useLineEdit: true property bool useLineEdit: true
property bool showFormatProperty: false property bool showFormatProperty: false
property bool showFontSizeMode: false
SectionLayout { SectionLayout {
columns: 2 columns: 2
@@ -62,6 +64,19 @@ Section {
model: ["NoWrap", "WordWrap", "WrapAnywhere", "WrapAtWordBoundaryOrAnywhere"] 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 { Label {
text: qsTr("Alignment") text: qsTr("Alignment")
} }
@@ -91,5 +106,27 @@ Section {
backendValue: backendValues.textFormat backendValue: backendValues.textFormat
Layout.fillWidth: true 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
}
} }
} }

View File

@@ -52,6 +52,13 @@ RowLayout {
Controls.ComboBox { Controls.ComboBox {
id: comboBox id: comboBox
ExtendedFunctionButton {
x: 2
anchors.verticalCenter: parent.verticalCenter
backendValue: urlChooser.backendValue
visible: comboBox.enabled
}
property bool isComplete: false property bool isComplete: false
function setCurrentText(text) { function setCurrentText(text) {

View File

@@ -38,3 +38,4 @@ Tab 2.0 Tab.qml
TabView 2.0 TabView.qml TabView 2.0 TabView.qml
ToolTipArea 2.0 ToolTipArea.qml ToolTipArea 2.0 ToolTipArea.qml
UrlChooser 2.0 UrlChooser.qml UrlChooser 2.0 UrlChooser.qml
PaddingSection 2.0 PaddingSection.qml

View File

@@ -78,8 +78,8 @@ Rectangle {
// right size after resizing to a wider width // right size after resizing to a wider width
Image { Image {
width: 16 Layout.preferredWidth: 16
height: 16 Layout.preferredHeight: 16
source: hasAliasExport ? "image://icons/alias-export-checked" : "image://icons/alias-export-unchecked" source: hasAliasExport ? "image://icons/alias-export-checked" : "image://icons/alias-export-unchecked"
ToolTipArea { ToolTipArea {
anchors.fill: parent anchors.fill: parent

View File

@@ -68,4 +68,8 @@ Column {
TextInputSection { TextInputSection {
} }
PaddingSection {
visible: minorQtQuickVersion > 5
}
} }

View File

@@ -68,4 +68,9 @@ Column {
TextInputSection { TextInputSection {
isTextInput: true isTextInput: true
} }
PaddingSection {
visible: minorQtQuickVersion > 5
}
} }

View File

@@ -36,6 +36,8 @@ Column {
showIsWrapping: true showIsWrapping: true
showVerticalAlignment: true showVerticalAlignment: true
showFormatProperty: true showFormatProperty: true
showElide: true
showFontSizeMode: true
} }
Section { Section {
@@ -66,4 +68,8 @@ Column {
FontSection { FontSection {
showStyle: true showStyle: true
} }
PaddingSection {
visible: minorQtQuickVersion > 5
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -28,8 +28,7 @@
namespace ClangBackEnd { namespace ClangBackEnd {
LinePrefixer::LinePrefixer(const QByteArray &prefix) LinePrefixer::LinePrefixer(const QByteArray &prefix)
: m_prefix(prefix), : m_prefix(prefix)
m_previousIsEndingWithNewLine(true)
{} {}
void LinePrefixer::setPrefix(const QByteArray &prefix) void LinePrefixer::setPrefix(const QByteArray &prefix)

View File

@@ -43,7 +43,7 @@ public:
private: private:
QByteArray m_prefix; QByteArray m_prefix;
bool m_previousIsEndingWithNewLine; bool m_previousIsEndingWithNewLine = true;
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -101,25 +101,22 @@ static inline std::string fixInnerType(const std::string &type,
// Return size from an STL vector (last/first iterators). // Return size from an STL vector (last/first iterators).
static inline int msvcStdVectorSize(const SymbolGroupValue &v) static inline int msvcStdVectorSize(const SymbolGroupValue &v)
{ {
// MSVC2012 has 2 base classes, MSVC2010 1, MSVC2008 none const ULONG64 firstPtr = v.readPointerValueFromAncestor("_Myfirst");
if (const SymbolGroupValue myFirstPtrV = SymbolGroupValue::findMember(v, "_Myfirst")) { const ULONG64 lastPtr = v.readPointerValueFromAncestor("_Mylast");
if (const SymbolGroupValue myLastPtrV = myFirstPtrV.parent()["_Mylast"]) {
const ULONG64 firstPtr = myFirstPtrV.pointerValue();
const ULONG64 lastPtr = myLastPtrV.pointerValue();
if (!firstPtr || lastPtr < firstPtr) if (!firstPtr || lastPtr < firstPtr)
return -1; 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) if (lastPtr == firstPtr)
return 0; return 0;
// Subtract the pointers: We need to do the pointer arithmetics ourselves // Subtract the pointers: We need to do the pointer arithmetics ourselves
// as we get char *pointers. // 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 static_cast<int>((lastPtr - firstPtr) / size);
}
}
return -1;
} }
// Return size of container or -1 // Return size of container or -1
@@ -193,10 +190,12 @@ int containerSize(KnownType kt, const SymbolGroupValue &v)
case KT_StdMap: case KT_StdMap:
case KT_StdMultiMap: case KT_StdMultiMap:
case KT_StdValArray: case KT_StdValArray:
case KT_StdList: case KT_StdList: {
if (const SymbolGroupValue size = SymbolGroupValue::findMember(v, "_Mysize")) const int size = v.readIntegerFromAncestor("_Mysize");
return size.intValue(); if (size >= 0)
return size;
break; break;
}
case KT_StdStack: case KT_StdStack:
if (const SymbolGroupValue deque = v[unsigned(0)]) if (const SymbolGroupValue deque = v[unsigned(0)])
return containerSize(KT_StdDeque, deque); return containerSize(KT_StdDeque, deque);

View File

@@ -53,11 +53,30 @@ PyObject *lookupType(const std::string &typeNameIn)
{ {
std::string typeName = typeNameIn; std::string typeName = typeNameIn;
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols(); 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; ULONG64 module;
ULONG typeId; ULONG typeId;
if (FAILED(symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module))) if (FAILED(symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module)))
Py_RETURN_NONE; 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) char *getTypeName(ULONG64 module, ULONG typeId)
@@ -93,7 +112,9 @@ PyObject *type_bitSize(Type *self)
{ {
ULONG size; ULONG size;
auto extcmd = ExtensionCommandContext::instance(); 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 NULL;
return Py_BuildValue("k", size * 8); return Py_BuildValue("k", size * 8);
} }
@@ -143,13 +164,8 @@ PyObject *type_Target(Type *self)
Py_XINCREF(self); Py_XINCREF(self);
return (PyObject *)self; return (PyObject *)self;
} }
typeName = typeName.substr(0, typeName.length() - 1); typeName.pop_back();
return lookupType(typeName);
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);
} }
PyObject *type_StripTypedef(Type *self) PyObject *type_StripTypedef(Type *self)
@@ -241,7 +257,7 @@ PyObject *type_TemplateArgument(Type *self, PyObject *args)
if (innerTypes.size() <= index) if (innerTypes.size() <= index)
Py_RETURN_NONE; Py_RETURN_NONE;
const std::string &innerType = innerTypes.at(index); const std::string &innerType = SymbolGroupValue::stripConst(innerTypes.at(index));
if (numeric) { if (numeric) {
try { try {
return Py_BuildValue("i", std::stoi(innerType)); return Py_BuildValue("i", std::stoi(innerType));
@@ -270,12 +286,12 @@ void type_Dealloc(Type *self)
delete[] self->m_name; 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 *type = PyObject_New(Type, type_pytype());
type->m_module = module; type->m_module = module;
type->m_typeId = typeId; type->m_typeId = typeId;
type->m_name = nullptr; type->m_name = name;
return reinterpret_cast<PyObject *>(type); return reinterpret_cast<PyObject *>(type);
} }

View File

@@ -44,4 +44,4 @@ PyTypeObject *type_pytype();
char *getTypeName(ULONG64 module, ULONG typeId); char *getTypeName(ULONG64 module, ULONG typeId);
PyObject *lookupType(const std::string &typeName); PyObject *lookupType(const std::string &typeName);
PyObject *createType(ULONG64 module, ULONG typeId); PyObject *createType(ULONG64 module, ULONG typeId, char *name = nullptr);

View File

@@ -154,6 +154,15 @@ int SymbolGroupValue::readIntegerFromAncestor(const std::string &name, int defau
return readPODFromAncestor<int>(name, defaultValue); 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 LONG64 SymbolGroupValue::offsetOfAncestor(const std::string &name) const
{ {
return infoOfAncestor(name).offset; return infoOfAncestor(name).offset;
@@ -204,7 +213,7 @@ SymbolAncestorInfo SymbolGroupValue::infoOfAncestor(const std::string &name) con
continue; continue;
info = child.infoOfAncestor(name); info = child.infoOfAncestor(name);
if (info.isValid()) { if (info.isValid()) {
info.offset += offsetOfAncestor(child.name()); info.offset += offsetOfChild(child);
break; break;
} }
} }

View File

@@ -71,6 +71,7 @@ public:
SymbolGroupValue operator[](const char *name) const; SymbolGroupValue operator[](const char *name) const;
SymbolGroupValue operator[](unsigned) const; SymbolGroupValue operator[](unsigned) const;
unsigned childCount() const; unsigned childCount() const;
ULONG64 offsetOfChild(const SymbolGroupValue &child) const;
SymbolGroupValue parent() const; SymbolGroupValue parent() const;
// take address and cast to desired (pointer) type // take address and cast to desired (pointer) type
SymbolGroupValue typeCast(const char *type) const; SymbolGroupValue typeCast(const char *type) const;

View File

@@ -269,7 +269,8 @@ QStringList Environment::appendExeExtensions(const QString &executable) const
} }
FileName Environment::searchInPath(const QString &executable, FileName Environment::searchInPath(const QString &executable,
const QStringList &additionalDirs) const const QStringList &additionalDirs,
bool (*func)(const QString &name)) const
{ {
if (executable.isEmpty()) if (executable.isEmpty())
return FileName(); return FileName();
@@ -292,7 +293,7 @@ FileName Environment::searchInPath(const QString &executable,
continue; continue;
alreadyChecked.insert(dir); alreadyChecked.insert(dir);
FileName tmp = searchInDirectory(execs, dir); FileName tmp = searchInDirectory(execs, dir);
if (!tmp.isEmpty()) if (!tmp.isEmpty() && (!func || func(tmp.toString())))
return tmp; return tmp;
} }
@@ -304,7 +305,7 @@ FileName Environment::searchInPath(const QString &executable,
continue; continue;
alreadyChecked.insert(p); alreadyChecked.insert(p);
FileName tmp = searchInDirectory(execs, QDir::fromNativeSeparators(p)); FileName tmp = searchInDirectory(execs, QDir::fromNativeSeparators(p));
if (!tmp.isEmpty()) if (!tmp.isEmpty() && (!func || func(tmp.toString())))
return tmp; return tmp;
} }
return FileName(); return FileName();

View File

@@ -100,7 +100,9 @@ public:
Environment::const_iterator constFind(const QString &name) const; Environment::const_iterator constFind(const QString &name) const;
FileName searchInPath(const QString &executable, 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 path() const;
QStringList appendExeExtensions(const QString &executable) const; QStringList appendExeExtensions(const QString &executable) const;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 B

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 B

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 211 B

View File

@@ -38,11 +38,16 @@
<file>images/compile_error_taskbar@2x.png</file> <file>images/compile_error_taskbar@2x.png</file>
<file>images/dir.png</file> <file>images/dir.png</file>
<file>images/editcopy.png</file> <file>images/editcopy.png</file>
<file>images/editcopy@2x.png</file>
<file>images/editcut.png</file> <file>images/editcut.png</file>
<file>images/editcut@2x.png</file>
<file>images/editpaste.png</file> <file>images/editpaste.png</file>
<file>images/editpaste@2x.png</file>
<file>images/empty14.png</file> <file>images/empty14.png</file>
<file>images/filenew.png</file> <file>images/filenew.png</file>
<file>images/filenew@2x.png</file>
<file>images/fileopen.png</file> <file>images/fileopen.png</file>
<file>images/fileopen@2x.png</file>
<file>images/filesave.png</file> <file>images/filesave.png</file>
<file>images/filesave@2x.png</file> <file>images/filesave@2x.png</file>
<file>images/inputfield.png</file> <file>images/inputfield.png</file>

View File

@@ -64,10 +64,10 @@ const Icon BOOKMARK_TOOLBAR({
const Icon BOOKMARK_TEXTEDITOR({ const Icon BOOKMARK_TEXTEDITOR({
{QLatin1String(":/utils/images/bookmark.png"), Theme::Bookmarks_TextMarkColor}}, Icon::Tint); {QLatin1String(":/utils/images/bookmark.png"), Theme::Bookmarks_TextMarkColor}}, Icon::Tint);
const Icon NEWFILE( const Icon NEWFILE({
QLatin1String(":/utils/images/filenew.png")); {QLatin1String(":/utils/images/filenew.png"), Theme::PanelTextColorMid}}, Icon::Tint);
const Icon OPENFILE( const Icon OPENFILE({
QLatin1String(":/utils/images/fileopen.png")); {QLatin1String(":/utils/images/fileopen.png"), Theme::PanelTextColorMid}}, Icon::Tint);
const Icon SAVEFILE({ const Icon SAVEFILE({
{QLatin1String(":/utils/images/filesave.png"), Theme::PanelTextColorMid}}, Icon::Tint); {QLatin1String(":/utils/images/filesave.png"), Theme::PanelTextColorMid}}, Icon::Tint);
const Icon SAVEFILE_TOOLBAR({ const Icon SAVEFILE_TOOLBAR({
@@ -76,12 +76,12 @@ const Icon UNDO({
{QLatin1String(":/utils/images/undo.png"), Theme::PanelTextColorMid}}, Icon::Tint); {QLatin1String(":/utils/images/undo.png"), Theme::PanelTextColorMid}}, Icon::Tint);
const Icon REDO({ const Icon REDO({
{QLatin1String(":/utils/images/redo.png"), Theme::PanelTextColorMid}}, Icon::Tint); {QLatin1String(":/utils/images/redo.png"), Theme::PanelTextColorMid}}, Icon::Tint);
const Icon COPY( const Icon COPY({
QLatin1String(":/utils/images/editcopy.png")); {QLatin1String(":/utils/images/editcopy.png"), Theme::PanelTextColorMid}}, Icon::Tint);
const Icon PASTE( const Icon PASTE({
QLatin1String(":/utils/images/editpaste.png")); {QLatin1String(":/utils/images/editpaste.png"), Theme::PanelTextColorMid}}, Icon::Tint);
const Icon CUT( const Icon CUT({
QLatin1String(":/utils/images/editcut.png")); {QLatin1String(":/utils/images/editcut.png"), Theme::PanelTextColorMid}}, Icon::Tint);
const Icon DIR( const Icon DIR(
QLatin1String(":/utils/images/dir.png")); QLatin1String(":/utils/images/dir.png"));
const Icon RESET({ const Icon RESET({

View File

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>397</width> <width>449</width>
<height>205</height> <height>210</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -17,16 +17,8 @@
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QCheckBox" name="runDisabledGTestsCB"> <layout class="QGridLayout" name="gridLayout">
<property name="toolTip"> <item row="1" column="0">
<string>Executes disabled tests when performing a test run.</string>
</property>
<property name="text">
<string>Run disabled tests</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="breakOnFailureCB"> <widget class="QCheckBox" name="breakOnFailureCB">
<property name="toolTip"> <property name="toolTip">
<string>Turn failures into debugger breakpoints.</string> <string>Turn failures into debugger breakpoints.</string>
@@ -39,35 +31,30 @@
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <widget class="QCheckBox" name="runDisabledGTestsCB">
<item>
<widget class="QCheckBox" name="repeatGTestsCB">
<property name="toolTip"> <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>
<property name="text"> <property name="text">
<string>Repeat tests</string> <string>Run disabled tests</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="4" column="0">
<spacer name="horizontalSpacer_2"> <widget class="QCheckBox" name="throwOnFailureCB">
<property name="orientation"> <property name="toolTip">
<enum>Qt::Horizontal</enum> <string>Turn assertion failures into C++ exceptions.</string>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="text">
<size> <string>Throw on failure</string>
<width>40</width>
<height>20</height>
</size>
</property> </property>
</spacer> </widget>
</item> </item>
<item> <item row="2" column="1">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@@ -77,7 +64,27 @@
</property> </property>
</widget> </widget>
</item> </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"> <widget class="QSpinBox" name="repetitionSpin">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
@@ -90,50 +97,10 @@
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="3" column="1">
<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>
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@@ -143,7 +110,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="3" column="2">
<widget class="QSpinBox" name="seedSpin"> <widget class="QSpinBox" name="seedSpin">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
@@ -159,31 +126,8 @@
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </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> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">

View File

@@ -36,9 +36,6 @@
<property name="title"> <property name="title">
<string>Benchmark Metrics</string> <string>Benchmark Metrics</string>
</property> </property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
<widget class="QRadioButton" name="walltimeRB"> <widget class="QRadioButton" name="walltimeRB">

View File

@@ -237,7 +237,7 @@ QList<TestConfiguration *> QuickTestTreeItem::getSelectedTestConfigurations() co
int grandChildCount = child->childCount(); int grandChildCount = child->childCount();
for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) { for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) {
const TestTreeItem *grandChild = child->childItem(grandChildRow); const TestTreeItem *grandChild = child->childItem(grandChildRow);
if (grandChild->type() != TestFunctionOrSet) if (grandChild->checked() != Qt::Checked || grandChild->type() != TestFunctionOrSet)
continue; continue;
testFunctions << child->name() + "::" + grandChild->name(); testFunctions << child->name() + "::" + grandChild->name();
} }

View File

@@ -15,7 +15,6 @@ QtcPlugin {
"bookmark.h", "bookmark.h",
"bookmarkmanager.cpp", "bookmarkmanager.cpp",
"bookmarkmanager.h", "bookmarkmanager.h",
"bookmarks.qrc",
"bookmarks_global.h", "bookmarks_global.h",
"bookmarksplugin.cpp", "bookmarksplugin.cpp",
"bookmarksplugin.h", "bookmarksplugin.h",

View File

@@ -38,7 +38,6 @@
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QRegularExpression>
#include <QStringList> #include <QStringList>
using namespace ClangCodeModel; using namespace ClangCodeModel;
@@ -100,7 +99,7 @@ public:
optionsBuilder.addPredefinedMacrosAndHeaderPathsOptions(); optionsBuilder.addPredefinedMacrosAndHeaderPathsOptions();
optionsBuilder.addWrappedQtHeadersIncludePath(); optionsBuilder.addWrappedQtHeadersIncludePath();
optionsBuilder.addHeaderPathOptions(/*addAsNativePath*/ true); optionsBuilder.addHeaderPathOptions();
optionsBuilder.addProjectConfigFileInclude(); optionsBuilder.addProjectConfigFileInclude();
optionsBuilder.addMsvcCompatibilityVersion(); optionsBuilder.addMsvcCompatibilityVersion();
@@ -118,18 +117,12 @@ private:
bool excludeHeaderPath(const QString &path) const override 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"))) if (path.contains(QLatin1String("lib/gcc/i686-apple-darwin")))
return true; return true;
}
// We already provide a custom clang include path matching the used libclang version, return CompilerOptionsBuilder::excludeHeaderPath(path);
// 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;
} }
void addPredefinedMacrosAndHeaderPathsOptions() void addPredefinedMacrosAndHeaderPathsOptions()

View File

@@ -56,18 +56,12 @@ RefactoringCompilerOptionsBuilder::RefactoringCompilerOptionsBuilder(CppTools::P
bool RefactoringCompilerOptionsBuilder::excludeHeaderPath(const QString &path) const 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"))) if (path.contains(QLatin1String("lib/gcc/i686-apple-darwin")))
return true; return true;
}
// We already provide a custom clang include path matching the used libclang version, return CompilerOptionsBuilder::excludeHeaderPath(path);
// 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;
} }
void RefactoringCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptions() void RefactoringCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptions()

View File

@@ -34,7 +34,6 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <QDir> #include <QDir>
#include <QRegularExpression>
namespace ClangRefactoring { namespace ClangRefactoring {

View File

@@ -107,7 +107,8 @@ void ClangStaticAnalyzerPreconfiguredSessionTests::testPreconfiguredSession()
QSignalSpy waitUntilAnalyzerFinished(&m_analyzerTool, SIGNAL(finished(bool))); QSignalSpy waitUntilAnalyzerFinished(&m_analyzerTool, SIGNAL(finished(bool)));
QVERIFY(waitUntilAnalyzerFinished.wait(30000)); QVERIFY(waitUntilAnalyzerFinished.wait(30000));
const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst(); const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst();
QVERIFY(arguments.first().toBool()); const bool analyzerFinishedSuccessfully = arguments.first().toBool();
QVERIFY(analyzerFinishedSuccessfully);
QCOMPARE(m_analyzerTool.diagnostics().count(), 0); QCOMPARE(m_analyzerTool.diagnostics().count(), 0);
} }

View File

@@ -182,7 +182,7 @@ public:
const Core::Id type = projectPart.toolchainType; const Core::Id type = projectPart.toolchainType;
if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|| type == ProjectExplorer::Constants::GCC_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) if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
optionsBuilder.addDefines(projectPart.toolchainDefines); optionsBuilder.addDefines(projectPart.toolchainDefines);

View File

@@ -63,7 +63,7 @@ static QStringList constructCommandLineArguments(const QString &filePath,
arguments arguments
<< QLatin1String("--analyze") << QLatin1String("--analyze")
<< QLatin1String("-o") << QLatin1String("-o")
<< logFile << QDir::toNativeSeparators(logFile)
; ;
arguments += options; arguments += options;
arguments << QDir::toNativeSeparators(filePath); arguments << QDir::toNativeSeparators(filePath);
@@ -80,7 +80,7 @@ ClangStaticAnalyzerRunner::ClangStaticAnalyzerRunner(const QString &clangExecuta
const Utils::Environment &environment, const Utils::Environment &environment,
QObject *parent) QObject *parent)
: QObject(parent) : QObject(parent)
, m_clangExecutable(clangExecutable) , m_clangExecutable(QDir::toNativeSeparators(clangExecutable))
, m_clangLogFileDir(clangLogFileDir) , m_clangLogFileDir(clangLogFileDir)
{ {
QTC_CHECK(!m_clangExecutable.isEmpty()); QTC_CHECK(!m_clangExecutable.isEmpty());

View File

@@ -1970,6 +1970,7 @@ void EditorManagerPrivate::autoSave()
if (!errors.isEmpty()) if (!errors.isEmpty())
QMessageBox::critical(ICore::mainWindow(), tr("File Error"), QMessageBox::critical(ICore::mainWindow(), tr("File Error"),
errors.join(QLatin1Char('\n'))); errors.join(QLatin1Char('\n')));
emit m_instance->autoSaved();
} }
void EditorManagerPrivate::handleContextChange(const QList<IContext *> &context) void EditorManagerPrivate::handleContextChange(const QList<IContext *> &context)

View File

@@ -185,6 +185,7 @@ signals:
void editorsClosed(QList<Core::IEditor *> editors); void editorsClosed(QList<Core::IEditor *> editors);
void findOnFileSystemRequest(const QString &path); void findOnFileSystemRequest(const QString &path);
void aboutToSave(IDocument *document); void aboutToSave(IDocument *document);
void autoSaved();
public slots: public slots:
static void saveDocument(); static void saveDocument();

View File

@@ -68,11 +68,6 @@ void InfoBarEntry::setCancelButtonInfo(const QString &_cancelButtonText, CallBac
m_cancelButtonCallBack = callBack; m_cancelButtonCallBack = callBack;
} }
void InfoBarEntry::setSuppressionButtonInfo(InfoBarEntry::CallBack callback)
{
m_suppressionButtonCallBack = callback;
}
void InfoBarEntry::setShowDefaultCancelButton(bool yesno) void InfoBarEntry::setShowDefaultCancelButton(bool yesno)
{ {
m_showDefaultCancelButton = yesno; m_showDefaultCancelButton = yesno;
@@ -282,9 +277,7 @@ void InfoBarDisplay::update()
if (info.globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) { if (info.globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) {
infoWidgetSuppressButton = new QToolButton; infoWidgetSuppressButton = new QToolButton;
infoWidgetSuppressButton->setText(tr("Do Not Show Again")); infoWidgetSuppressButton->setText(tr("Do Not Show Again"));
connect(infoWidgetSuppressButton, &QAbstractButton::clicked, this, [this, info, id] { connect(infoWidgetSuppressButton, &QAbstractButton::clicked, this, [this, id] {
if (info.m_suppressionButtonCallBack)
info.m_suppressionButtonCallBack();
m_infoBar->removeInfo(id); m_infoBar->removeInfo(id);
InfoBar::globallySuppressInfo(id); InfoBar::globallySuppressInfo(id);
}); });

View File

@@ -58,7 +58,6 @@ public:
void setCustomButtonInfo(const QString &_buttonText, CallBack callBack); void setCustomButtonInfo(const QString &_buttonText, CallBack callBack);
void setCancelButtonInfo(CallBack callBack); void setCancelButtonInfo(CallBack callBack);
void setCancelButtonInfo(const QString &_cancelButtonText, CallBack callBack); void setCancelButtonInfo(const QString &_cancelButtonText, CallBack callBack);
void setSuppressionButtonInfo(CallBack callback);
void setShowDefaultCancelButton(bool yesno); void setShowDefaultCancelButton(bool yesno);
using DetailsWidgetCreator = std::function<QWidget*()>; using DetailsWidgetCreator = std::function<QWidget*()>;
@@ -71,7 +70,6 @@ private:
CallBack m_buttonCallBack; CallBack m_buttonCallBack;
QString cancelButtonText; QString cancelButtonText;
CallBack m_cancelButtonCallBack; CallBack m_cancelButtonCallBack;
CallBack m_suppressionButtonCallBack;
GlobalSuppressionMode globalSuppression; GlobalSuppressionMode globalSuppression;
DetailsWidgetCreator m_detailsWidgetCreator; DetailsWidgetCreator m_detailsWidgetCreator;
bool m_showDefaultCancelButton = true; bool m_showDefaultCancelButton = true;

View File

@@ -56,6 +56,7 @@
#include <cpptools/cpptoolsconstants.h> #include <cpptools/cpptoolsconstants.h>
#include <cpptools/cpptoolsplugin.h> #include <cpptools/cpptoolsplugin.h>
#include <cpptools/cpptoolsreuse.h> #include <cpptools/cpptoolsreuse.h>
#include <cpptools/cpptoolssettings.h>
#include <cpptools/cppworkingcopy.h> #include <cpptools/cppworkingcopy.h>
#include <cpptools/symbolfinder.h> #include <cpptools/symbolfinder.h>
#include <cpptools/refactoringengineinterface.h> #include <cpptools/refactoringengineinterface.h>
@@ -130,7 +131,7 @@ public:
QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor; QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
QToolButton *m_preprocessorButton = nullptr; QToolButton *m_preprocessorButton = nullptr;
QToolButton *m_headerErrorsIndicatorButton = nullptr; QAction *m_headerErrorsIndicatorAction = nullptr;
CppSelectionChanger m_cppSelectionChanger; CppSelectionChanger m_cppSelectionChanger;
@@ -229,15 +230,20 @@ void CppEditorWidget::finalizeInitialization()
connect(cmd, &Command::keySequenceChanged, this, &CppEditorWidget::updatePreprocessorButtonTooltip); connect(cmd, &Command::keySequenceChanged, this, &CppEditorWidget::updatePreprocessorButtonTooltip);
updatePreprocessorButtonTooltip(); updatePreprocessorButtonTooltip();
connect(d->m_preprocessorButton, &QAbstractButton::clicked, this, &CppEditorWidget::showPreProcessorWidget); 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_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()); insertExtraToolBarWidget(TextEditorWidget::Left, d->m_cppEditorOutline->widget());
} }
@@ -252,6 +258,10 @@ void CppEditorWidget::finalizeInitializationAfterDuplication(TextEditorWidget *o
d->m_cppEditorOutline->update(); d->m_cppEditorOutline->update();
const Id selectionKind = CodeWarningsSelection; const Id selectionKind = CodeWarningsSelection;
setExtraSelections(selectionKind, cppEditorWidget->extraSelections(selectionKind)); setExtraSelections(selectionKind, cppEditorWidget->extraSelections(selectionKind));
d->m_headerErrorDiagnosticWidgetCreator
= cppEditorWidget->d->m_headerErrorDiagnosticWidgetCreator;
updateHeaderErrorWidgets();
} }
CppEditorWidget::~CppEditorWidget() CppEditorWidget::~CppEditorWidget()
@@ -329,13 +339,14 @@ void CppEditorWidget::updateHeaderErrorWidgets()
infoBar->removeInfo(id); infoBar->removeInfo(id);
if (d->m_headerErrorDiagnosticWidgetCreator) { if (d->m_headerErrorDiagnosticWidgetCreator) {
if (infoBar->canInfoBeAdded(id)) { if (CppToolsSettings::instance()->showHeaderErrorInfoBar()) {
addHeaderErrorInfoBarEntryAndHideIndicator(); addHeaderErrorInfoBarEntry();
d->m_headerErrorsIndicatorAction->setVisible(false);
} else { } else {
d->m_headerErrorsIndicatorButton->setEnabled(true); d->m_headerErrorsIndicatorAction->setVisible(true);
} }
} else { } 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 renameUsages(); // Rename non-local symbol or macro
} }
void CppEditorWidget::addHeaderErrorInfoBarEntryAndHideIndicator() const void CppEditorWidget::addHeaderErrorInfoBarEntry() const
{ {
InfoBarEntry info(Constants::ERRORS_IN_HEADER_FILES, InfoBarEntry info(Constants::ERRORS_IN_HEADER_FILES,
tr("<b>Warning</b>: The code model could not parse an included file, " tr("<b>Warning</b>: The code model could not parse an included file, "
"which might lead to slow or incorrect code completion and " "which might lead to slow or incorrect code completion and "
"highlighting, for example."), "highlighting, for example."));
InfoBarEntry::GlobalSuppressionEnabled);
info.setDetailsWidgetCreator(d->m_headerErrorDiagnosticWidgetCreator); info.setDetailsWidgetCreator(d->m_headerErrorDiagnosticWidgetCreator);
info.setShowDefaultCancelButton(false); info.setShowDefaultCancelButton(false);
info.setSuppressionButtonInfo([this](){ info.setCustomButtonInfo("Minimize", [](){
d->m_headerErrorsIndicatorButton->setEnabled(true); CppToolsSettings::instance()->setShowHeaderErrorInfoBar(false);
}); });
InfoBar *infoBar = textDocument()->infoBar(); InfoBar *infoBar = textDocument()->infoBar();
infoBar->addInfo(info); infoBar->addInfo(info);
d->m_headerErrorsIndicatorButton->setEnabled(false);
} }
namespace { 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 Internal
} // namespace CppEditor } // namespace CppEditor

View File

@@ -31,10 +31,6 @@
#include <QScopedPointer> #include <QScopedPointer>
namespace Core {
class InfoBarEntry;
}
namespace CppTools { namespace CppTools {
class CppEditorOutline; class CppEditorOutline;
class RefactoringEngineInterface; class RefactoringEngineInterface;
@@ -91,7 +87,6 @@ public:
void switchDeclarationDefinition(bool inNextSplit); void switchDeclarationDefinition(bool inNextSplit);
void showPreProcessorWidget(); void showPreProcessorWidget();
void showHeaderErrorInfoBar();
void findUsages(); void findUsages();
void renameSymbolUnderCursor(); void renameSymbolUnderCursor();
@@ -150,7 +145,7 @@ private:
void renameSymbolUnderCursorClang(); void renameSymbolUnderCursorClang();
void renameSymbolUnderCursorBuiltin(); void renameSymbolUnderCursorBuiltin();
void addHeaderErrorInfoBarEntryAndHideIndicator() const; void addHeaderErrorInfoBarEntry() const;
CppTools::ProjectPart *projectPart() const; CppTools::ProjectPart *projectPart() const;

View File

@@ -28,6 +28,7 @@
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <QDir> #include <QDir>
#include <QRegularExpression>
namespace CppTools { namespace CppTools {
@@ -100,7 +101,7 @@ void CompilerOptionsBuilder::enableExceptions()
add(QLatin1String("-fexceptions")); add(QLatin1String("-fexceptions"));
} }
void CompilerOptionsBuilder::addHeaderPathOptions(bool addAsNativePath) void CompilerOptionsBuilder::addHeaderPathOptions()
{ {
typedef ProjectPartHeaderPath HeaderPath; typedef ProjectPartHeaderPath HeaderPath;
const QString defaultPrefix = includeOption(); const QString defaultPrefix = includeOption();
@@ -126,10 +127,7 @@ void CompilerOptionsBuilder::addHeaderPathOptions(bool addAsNativePath)
break; break;
} }
QString path = prefix + headerPath.path; result.append(prefix + QDir::toNativeSeparators(headerPath.path));
path = addAsNativePath ? QDir::toNativeSeparators(path) : path;
result.append(path);
} }
m_options.append(result); m_options.append(result);
@@ -393,7 +391,15 @@ bool CompilerOptionsBuilder::excludeDefineLine(const QByteArray &defineLine) con
bool CompilerOptionsBuilder::excludeHeaderPath(const QString &headerPath) const 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; return false;
} }

View File

@@ -46,7 +46,7 @@ public:
// Add options based on project part // Add options based on project part
virtual void addTargetTriple(); virtual void addTargetTriple();
virtual void enableExceptions(); virtual void enableExceptions();
void addHeaderPathOptions(bool addAsNativePath = false); void addHeaderPathOptions();
void addToolchainAndProjectDefines(); void addToolchainAndProjectDefines();
void addDefines(const QByteArray &defineDirectives); void addDefines(const QByteArray &defineDirectives);
virtual void addLanguageOption(ProjectFile::Kind fileKind); virtual void addLanguageOption(ProjectFile::Kind fileKind);

View File

@@ -49,6 +49,7 @@ const char CPPTOOLS_SETTINGSGROUP[] = "CppTools";
const char LOWERCASE_CPPFILES_KEY[] = "LowerCaseFiles"; const char LOWERCASE_CPPFILES_KEY[] = "LowerCaseFiles";
enum { lowerCaseFilesDefault = 1 }; enum { lowerCaseFilesDefault = 1 };
const char CPPTOOLS_SORT_EDITOR_DOCUMENT_OUTLINE[] = "SortedMethodOverview"; 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_MODEL_MANAGER_PCH_USAGE[] = "PCHUsage";
const char CPPTOOLS_SKIP_INDEXING_BIG_FILES[] = "SkipIndexingBigFiles"; const char CPPTOOLS_SKIP_INDEXING_BIG_FILES[] = "SkipIndexingBigFiles";
const char CPPTOOLS_INDEXER_FILE_SIZE_LIMIT[] = "IndexerFileSizeLimit"; const char CPPTOOLS_INDEXER_FILE_SIZE_LIMIT[] = "IndexerFileSizeLimit";

View File

@@ -267,3 +267,21 @@ void CppToolsSettings::setSortedEditorDocumentOutline(bool sorted)
ICore::settings()->setValue(sortEditorDocumentOutlineKey(), sorted); ICore::settings()->setValue(sortEditorDocumentOutlineKey(), sorted);
emit editorDocumentOutlineSortingChanged(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);
}

View File

@@ -63,8 +63,12 @@ public:
bool sortedEditorDocumentOutline() const; bool sortedEditorDocumentOutline() const;
void setSortedEditorDocumentOutline(bool sorted); void setSortedEditorDocumentOutline(bool sorted);
bool showHeaderErrorInfoBar() const;
void setShowHeaderErrorInfoBar(bool show);
signals: signals:
void editorDocumentOutlineSortingChanged(bool isSorted); void editorDocumentOutlineSortingChanged(bool isSorted);
void showHeaderErrorInfoBarChanged(bool isShown);
private: private:
Internal::CppToolsSettingsPrivate *d; Internal::CppToolsSettingsPrivate *d;

View File

@@ -2374,6 +2374,7 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro
QTC_ASSERT(parent, return); QTC_ASSERT(parent, return);
LookupItems itemsToLookup; LookupItems itemsToLookup;
const QSet<QString> expandedINames = engine->watchHandler()->expandedINames();
foreach (const QVariant &property, properties) { foreach (const QVariant &property, properties) {
QmlV8ObjectData propertyData = extractData(property); QmlV8ObjectData propertyData = extractData(property);
auto item = new WatchItem; auto item = new WatchItem;
@@ -2395,7 +2396,7 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro
item->id = propertyData.handle; item->id = propertyData.handle;
item->type = propertyData.type; item->type = propertyData.type;
item->value = propertyData.value.toString(); 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}); itemsToLookup.insert(propertyData.handle, {item->iname, item->name, item->exp});
item->setHasChildren(propertyData.properties.count() > 0); item->setHasChildren(propertyData.properties.count() > 0);
parent->appendChild(item); parent->appendChild(item);

View File

@@ -33,7 +33,8 @@ HEADERS += \
iosdeploystep.h \ iosdeploystep.h \
iosdeploystepfactory.h \ iosdeploystepfactory.h \
iosdeploystepwidget.h \ iosdeploystepwidget.h \
iosanalyzesupport.h iosanalyzesupport.h \
simulatorcontrol.h
SOURCES += \ SOURCES += \
@@ -61,7 +62,8 @@ SOURCES += \
iosdeploystep.cpp \ iosdeploystep.cpp \
iosdeploystepfactory.cpp \ iosdeploystepfactory.cpp \
iosdeploystepwidget.cpp \ iosdeploystepwidget.cpp \
iosanalyzesupport.cpp iosanalyzesupport.cpp \
simulatorcontrol.cpp
FORMS += \ FORMS += \
iossettingswidget.ui \ iossettingswidget.ui \

View File

@@ -69,6 +69,8 @@ QtcPlugin {
"iossimulatorfactory.cpp", "iossimulatorfactory.cpp",
"iossimulatorfactory.h", "iossimulatorfactory.h",
"iostoolhandler.cpp", "iostoolhandler.cpp",
"iostoolhandler.h" "iostoolhandler.h",
"simulatorcontrol.cpp",
"simulatorcontrol.h"
] ]
} }

View File

@@ -27,6 +27,7 @@
#include "iosconstants.h" #include "iosconstants.h"
#include "iosdevice.h" #include "iosdevice.h"
#include "iossimulator.h" #include "iossimulator.h"
#include "simulatorcontrol.h"
#include "iosprobe.h" #include "iosprobe.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -332,7 +333,7 @@ void IosConfigurations::updateSimulators()
dev = IDevice::ConstPtr(new IosSimulator(devId)); dev = IDevice::ConstPtr(new IosSimulator(devId));
devManager->addDevice(dev); devManager->addDevice(dev);
} }
IosSimulator::updateAvailableDevices(); SimulatorControl::updateAvailableSimulators();
} }
void IosConfigurations::setDeveloperPath(const FileName &devPath) void IosConfigurations::setDeveloperPath(const FileName &devPath)

View File

@@ -169,6 +169,8 @@ IosDebugSupport::IosDebugSupport(IosRunConfiguration *runConfig,
m_runner, &IosRunner::start); m_runner, &IosRunner::start);
connect(m_runControl, &RunControl::finished, connect(m_runControl, &RunControl::finished,
m_runner, &IosRunner::stop); m_runner, &IosRunner::stop);
connect(m_runControl, &DebuggerRunControl::stateChanged,
m_runner, &IosRunner::debuggerStateChanged);
connect(m_runner, &IosRunner::gotServerPorts, connect(m_runner, &IosRunner::gotServerPorts,
this, &IosDebugSupport::handleServerPorts); this, &IosDebugSupport::handleServerPorts);

View File

@@ -101,7 +101,12 @@ bool IosDeployStep::init(QList<const BuildStep *> &earlierSteps)
this->target()->activeRunConfiguration()); this->target()->activeRunConfiguration());
QTC_ASSERT(runConfig, return false); QTC_ASSERT(runConfig, return false);
m_bundlePath = runConfig->bundleDirectory().toString(); 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."), emit addOutput(tr("Error: no device available, deploy failed."),
BuildStep::ErrorMessageOutput); BuildStep::ErrorMessageOutput);
return false; return false;
@@ -113,17 +118,15 @@ void IosDeployStep::run(QFutureInterface<bool> &fi)
{ {
m_futureInterface = fi; m_futureInterface = fi;
QTC_CHECK(m_transferStatus == NoTransfer); QTC_CHECK(m_transferStatus == NoTransfer);
if (iosdevice().isNull()) { if (device().isNull()) {
if (iossimulator().isNull())
TaskHub::addTask(Task::Error, tr("Deployment failed. No iOS device found."), TaskHub::addTask(Task::Error, tr("Deployment failed. No iOS device found."),
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT); ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
reportRunResult(m_futureInterface, !iossimulator().isNull()); reportRunResult(m_futureInterface, !iossimulator().isNull());
cleanup(); cleanup();
return; return;
} }
m_toolHandler = new IosToolHandler(m_deviceType, this);
m_transferStatus = TransferInProgress; m_transferStatus = TransferInProgress;
QTC_CHECK(m_toolHandler == 0);
m_toolHandler = new IosToolHandler(IosDeviceType(IosDeviceType::IosDevice), this);
m_futureInterface.setProgressRange(0, 200); m_futureInterface.setProgressRange(0, 200);
m_futureInterface.setProgressValueAndText(0, QLatin1String("Transferring application")); m_futureInterface.setProgressValueAndText(0, QLatin1String("Transferring application"));
m_futureInterface.reportStarted(); m_futureInterface.reportStarted();
@@ -136,7 +139,7 @@ void IosDeployStep::run(QFutureInterface<bool> &fi)
connect(m_toolHandler, &IosToolHandler::errorMsg, connect(m_toolHandler, &IosToolHandler::errorMsg,
this, &IosDeployStep::handleErrorMsg); this, &IosDeployStep::handleErrorMsg);
checkProvisioningProfile(); checkProvisioningProfile();
m_toolHandler->requestTransferApp(appBundle(), deviceId()); m_toolHandler->requestTransferApp(appBundle(), m_deviceType.identifier);
} }
void IosDeployStep::cancel() void IosDeployStep::cancel()
@@ -150,7 +153,7 @@ void IosDeployStep::cleanup()
QTC_CHECK(m_transferStatus != TransferInProgress); QTC_CHECK(m_transferStatus != TransferInProgress);
m_transferStatus = NoTransfer; m_transferStatus = NoTransfer;
m_device.clear(); m_device.clear();
m_toolHandler = 0; m_toolHandler = nullptr;
m_expectFail = false; m_expectFail = false;
} }

View File

@@ -101,6 +101,7 @@ private:
QFutureInterface<bool> m_futureInterface; QFutureInterface<bool> m_futureInterface;
ProjectExplorer::IDevice::ConstPtr m_device; ProjectExplorer::IDevice::ConstPtr m_device;
QString m_bundlePath; QString m_bundlePath;
IosDeviceType m_deviceType;
static const Core::Id Id; static const Core::Id Id;
bool m_expectFail; bool m_expectFail;
}; };

View File

@@ -27,6 +27,7 @@
#include "iosconstants.h" #include "iosconstants.h"
#include "iosmanager.h" #include "iosmanager.h"
#include "iosdeploystep.h" #include "iosdeploystep.h"
#include "simulatorcontrol.h"
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
@@ -346,7 +347,7 @@ IosDeviceType IosRunConfiguration::deviceType() const
{ {
QList<IosDeviceType> availableSimulators; QList<IosDeviceType> availableSimulators;
if (m_deviceType.type == IosDeviceType::SimulatedDevice) if (m_deviceType.type == IosDeviceType::SimulatedDevice)
availableSimulators = IosSimulator::availableDevices(); availableSimulators = SimulatorControl::availableSimulators();
if (!availableSimulators.isEmpty()) { if (!availableSimulators.isEmpty()) {
QList<IosDeviceType> elegibleDevices; QList<IosDeviceType> elegibleDevices;
QString devname = m_deviceType.identifier.split(QLatin1Char(',')).value(0); QString devname = m_deviceType.identifier.split(QLatin1Char(',')).value(0);
@@ -417,7 +418,7 @@ void IosRunConfigurationWidget::updateValues()
m_deviceTypeLabel->setVisible(showDeviceSelector); m_deviceTypeLabel->setVisible(showDeviceSelector);
m_deviceTypeComboBox->setVisible(showDeviceSelector); m_deviceTypeComboBox->setVisible(showDeviceSelector);
if (showDeviceSelector && m_deviceTypeModel.rowCount() == 0) { if (showDeviceSelector && m_deviceTypeModel.rowCount() == 0) {
foreach (const IosDeviceType &dType, IosSimulator::availableDevices()) { foreach (const IosDeviceType &dType, SimulatorControl::availableSimulators()) {
QStandardItem *item = new QStandardItem(dType.displayName); QStandardItem *item = new QStandardItem(dType.displayName);
QVariant v; QVariant v;
v.setValue(dType); v.setValue(dType);

View File

@@ -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, void IosRunner::handleDidStartApp(IosToolHandler *handler, const QString &bundlePath,
const QString &deviceId, IosToolHandler::OpStatus status) const QString &deviceId, IosToolHandler::OpStatus status)
{ {

View File

@@ -29,6 +29,7 @@
#include "iostoolhandler.h" #include "iostoolhandler.h"
#include "iossimulator.h" #include "iossimulator.h"
#include <debugger/debuggerconstants.h>
#include <projectexplorer/devicesupport/idevice.h> #include <projectexplorer/devicesupport/idevice.h>
#include <qmldebug/qmldebugcommandlinearguments.h> #include <qmldebug/qmldebugcommandlinearguments.h>
@@ -64,6 +65,9 @@ public:
void start(); void start();
void stop(); void stop();
public slots:
void debuggerStateChanged(Debugger::DebuggerState state);
signals: signals:
void didStartApp(Ios::IosToolHandler::OpStatus status); void didStartApp(Ios::IosToolHandler::OpStatus status);
void gotServerPorts(Utils::Port gdbPort, Utils::Port qmlPort); void gotServerPorts(Utils::Port gdbPort, Utils::Port qmlPort);

View File

@@ -45,9 +45,6 @@ static const QLatin1String iosDeviceTypeDisplayNameKey = QLatin1String("displayN
static const QLatin1String iosDeviceTypeTypeKey = QLatin1String("type"); static const QLatin1String iosDeviceTypeTypeKey = QLatin1String("type");
static const QLatin1String iosDeviceTypeIdentifierKey = QLatin1String("identifier"); static const QLatin1String iosDeviceTypeIdentifierKey = QLatin1String("identifier");
QMutex IosSimulator::_mutex;
QList<IosDeviceType> IosSimulator::_availableDevices;
IosSimulator::IosSimulator(Core::Id id) IosSimulator::IosSimulator(Core::Id id)
: IDevice(Core::Id(Constants::IOS_SIMULATOR_TYPE), : IDevice(Core::Id(Constants::IOS_SIMULATOR_TYPE),
IDevice::AutoDetected, IDevice::AutoDetected,
@@ -124,48 +121,6 @@ IDevice::Ptr IosSimulator::clone() const
return IDevice::Ptr(new IosSimulator(*this)); 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) void IosSimulator::fromMap(const QVariantMap &map)
{ {
IDevice::fromMap(map); IDevice::fromMap(map);

View File

@@ -67,10 +67,6 @@ public:
typedef QSharedPointer<IosSimulator> Ptr; typedef QSharedPointer<IosSimulator> Ptr;
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override; ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
static QList<IosDeviceType> availableDevices();
static void setAvailableDevices(QList<IosDeviceType> value);
static void updateAvailableDevices();
QString displayType() const override; QString displayType() const override;
ProjectExplorer::IDeviceWidget *createWidget() override; ProjectExplorer::IDeviceWidget *createWidget() override;
QList<Core::Id> actionIds() const override; QList<Core::Id> actionIds() const override;
@@ -91,8 +87,6 @@ protected:
IosSimulator(const IosSimulator &other); IosSimulator(const IosSimulator &other);
private: private:
mutable quint16 m_lastPort; mutable quint16 m_lastPort;
static QMutex _mutex;
static QList<IosDeviceType> _availableDevices;
}; };
namespace IosKitInformation { namespace IosKitInformation {

View File

@@ -27,13 +27,18 @@
#include "iosconfigurations.h" #include "iosconfigurations.h"
#include "iosconstants.h" #include "iosconstants.h"
#include "iossimulator.h" #include "iossimulator.h"
#include "simulatorcontrol.h"
#include "debugger/debuggerconstants.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileInfo> #include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QList> #include <QList>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QProcess> #include <QProcess>
@@ -52,6 +57,8 @@ namespace Ios {
namespace Internal { namespace Internal {
using namespace std::placeholders;
struct ParserState { struct ParserState {
enum Kind { enum Kind {
Msg, Msg,
@@ -132,7 +139,8 @@ public:
virtual void requestDeviceInfo(const QString &deviceId, int timeout = 1000) = 0; virtual void requestDeviceInfo(const QString &deviceId, int timeout = 1000) = 0;
bool isRunning(); bool isRunning();
void start(const QString &exe, const QStringList &args); 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 // signals
void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress, void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress,
@@ -148,15 +156,12 @@ public:
void appOutput(const QString &output); void appOutput(const QString &output);
void errorMsg(const QString &msg); void errorMsg(const QString &msg);
void toolExited(int code); 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; IosToolHandler *q;
QProcess *process; QProcess *process;
QTimer killTimer; QTimer killTimer;
@@ -176,34 +181,56 @@ class IosDeviceToolHandlerPrivate : public IosToolHandlerPrivate
{ {
public: public:
explicit IosDeviceToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q); explicit IosDeviceToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q);
virtual void requestTransferApp(const QString &bundlePath, const QString &deviceId,
int timeout = 1000); // IosToolHandlerPrivate overrides
virtual void requestRunApp(const QString &bundlePath, const QStringList &extraArgs, public:
void requestTransferApp(const QString &bundlePath, const QString &deviceId,
int timeout = 1000) override;
void requestRunApp(const QString &bundlePath, const QStringList &extraArgs,
IosToolHandler::RunKind runKind, IosToolHandler::RunKind runKind,
const QString &deviceId, int timeout = 1000); const QString &deviceId, int timeout = 1000) override;
virtual void requestDeviceInfo(const QString &deviceId, int timeout = 1000); void requestDeviceInfo(const QString &deviceId, int timeout = 1000) override;
virtual bool expectsFileDescriptor(); 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 class IosSimulatorToolHandlerPrivate : public IosToolHandlerPrivate
{ {
public: public:
explicit IosSimulatorToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q); explicit IosSimulatorToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q);
virtual void requestTransferApp(const QString &bundlePath, const QString &deviceId,
int timeout = 1000); // IosToolHandlerPrivate overrides
virtual void requestRunApp(const QString &bundlePath, const QStringList &extraArgs, public:
void requestTransferApp(const QString &bundlePath, const QString &deviceIdentifier,
int timeout = 1000) override;
void requestRunApp(const QString &bundlePath, const QStringList &extraArgs,
IosToolHandler::RunKind runKind, IosToolHandler::RunKind runKind,
const QString &deviceId, int timeout = 1000); const QString &deviceIdentifier, int timeout = 1000) override;
virtual void requestDeviceInfo(const QString &deviceId, int timeout = 1000); void requestDeviceInfo(const QString &deviceId, int timeout = 1000) override;
virtual bool expectsFileDescriptor(); void stop(int errorCode) override;
void debuggerStateChanged(Debugger::DebuggerState state) override;
private: 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, IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType,
Ios::IosToolHandler *q) : Ios::IosToolHandler *q) :
q(q), q(q),
process(new QProcess), process(nullptr),
state(NonStarted), state(NonStarted),
devType(devType), devType(devType),
iBegin(0), iBegin(0),
@@ -211,34 +238,6 @@ IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType,
gdbSocket(-1) gdbSocket(-1)
{ {
killTimer.setSingleShot(true); 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() IosToolHandlerPrivate::~IosToolHandlerPrivate()
@@ -258,6 +257,7 @@ bool IosToolHandlerPrivate::isRunning()
void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args) void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args)
{ {
Q_ASSERT(process);
QTC_CHECK(state == NonStarted); QTC_CHECK(state == NonStarted);
state = Starting; state = Starting;
qCDebug(toolHandlerLog) << "running " << exe << args; qCDebug(toolHandlerLog) << "running " << exe << args;
@@ -265,44 +265,6 @@ void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args)
state = StartedInferior; 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 // signals
void IosToolHandlerPrivate::isTransferringApp(const QString &bundlePath, const QString &deviceId, void IosToolHandlerPrivate::isTransferringApp(const QString &bundlePath, const QString &deviceId,
int progress, int maxProgress, const QString &info) int progress, int maxProgress, const QString &info)
@@ -355,7 +317,7 @@ void IosToolHandlerPrivate::toolExited(int code)
emit q->toolExited(q, code); emit q->toolExited(q, code);
} }
void IosToolHandlerPrivate::subprocessError(QProcess::ProcessError error) void IosDeviceToolHandlerPrivate::subprocessError(QProcess::ProcessError error)
{ {
if (state != Stopped) if (state != Stopped)
errorMsg(IosToolHandler::tr("iOS tool Error %1").arg(error)); 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 ); stop((exitStatus == QProcess::NormalExit) ? exitCode : -1 );
qCDebug(toolHandlerLog) << "IosToolHandler::finished(" << this << ")"; qCDebug(toolHandlerLog) << "IosToolHandler::finished(" << this << ")";
@@ -374,7 +336,7 @@ void IosToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatu
emit q->finished(q); emit q->finished(q);
} }
void IosToolHandlerPrivate::processXml() void IosDeviceToolHandlerPrivate::processXml()
{ {
while (!outputParser.atEnd()) { while (!outputParser.atEnd()) {
QXmlStreamReader::TokenType tt = outputParser.readNext(); QXmlStreamReader::TokenType tt = outputParser.readNext();
@@ -556,7 +518,7 @@ void IosToolHandlerPrivate::processXml()
} }
} }
void IosToolHandlerPrivate::subprocessHasData() void IosDeviceToolHandlerPrivate::subprocessHasData()
{ {
qCDebug(toolHandlerLog) << "subprocessHasData, state:" << state; qCDebug(toolHandlerLog) << "subprocessHasData, state:" << state;
while (true) { while (true) {
@@ -596,7 +558,42 @@ void IosToolHandlerPrivate::subprocessHasData()
IosDeviceToolHandlerPrivate::IosDeviceToolHandlerPrivate(const IosDeviceType &devType, IosDeviceToolHandlerPrivate::IosDeviceToolHandlerPrivate(const IosDeviceType &devType,
IosToolHandler *q) IosToolHandler *q)
: IosToolHandlerPrivate(devType, 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, void IosDeviceToolHandlerPrivate::requestTransferApp(const QString &bundlePath,
const QString &deviceId, int timeout) const QString &deviceId, int timeout)
@@ -644,11 +641,46 @@ void IosDeviceToolHandlerPrivate::requestDeviceInfo(const QString &deviceId, int
start(IosToolHandler::iosDeviceToolPath(), args); 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::IosSimulatorToolHandlerPrivate(const IosDeviceType &devType, IosSimulatorToolHandlerPrivate::IosSimulatorToolHandlerPrivate(const IosDeviceType &devType,
@@ -657,64 +689,159 @@ IosSimulatorToolHandlerPrivate::IosSimulatorToolHandlerPrivate(const IosDeviceTy
{ } { }
void IosSimulatorToolHandlerPrivate::requestTransferApp(const QString &bundlePath, void IosSimulatorToolHandlerPrivate::requestTransferApp(const QString &bundlePath,
const QString &deviceId, int timeout) const QString &deviceIdentifier, int timeout)
{ {
Q_UNUSED(timeout); Q_UNUSED(timeout);
this->bundlePath = bundlePath; this->bundlePath = bundlePath;
this->deviceId = deviceId; this->deviceId = deviceIdentifier;
emit didTransferApp(bundlePath, deviceId, IosToolHandler::Success); 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, void IosSimulatorToolHandlerPrivate::requestRunApp(const QString &bundlePath,
const QStringList &extraArgs, const QStringList &extraArgs,
IosToolHandler::RunKind runType, IosToolHandler::RunKind runType,
const QString &deviceId, int timeout) const QString &deviceIdentifier, int timeout)
{ {
Q_UNUSED(timeout); Q_UNUSED(timeout);
Q_UNUSED(deviceIdentifier);
this->bundlePath = bundlePath; this->bundlePath = bundlePath;
this->deviceId = deviceId; this->deviceId = devType.identifier;
this->runKind = runType; 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; 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) void IosSimulatorToolHandlerPrivate::requestDeviceInfo(const QString &deviceId, int timeout)
{ {
Q_UNUSED(timeout); Q_UNUSED(timeout);
this->deviceId = deviceId; Q_UNUSED(deviceId);
QStringList args;
args << QLatin1String("showdevicetypes");
op = OpDeviceInfo;
start(IosToolHandler::iosSimulatorToolPath(), args);
} }
bool IosSimulatorToolHandlerPrivate::expectsFileDescriptor() void IosSimulatorToolHandlerPrivate::stop(int errorCode)
{ {
return false; if (process) {
} if (isRunning()) {
process->terminate();
void IosSimulatorToolHandlerPrivate::addDeviceArguments(QStringList &args) const if (!process->waitForFinished(1000))
{ process->kill();
if (devType.type != IosDeviceType::SimulatedDevice) {
qCWarning(toolHandlerLog) << "IosSimulatorToolHandlerPrivate device type is not SimulatedDevice";
return;
} }
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() void IosToolHandlerPrivate::killProcess()
@@ -731,18 +858,6 @@ QString IosToolHandler::iosDeviceToolPath()
return res; 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) : IosToolHandler::IosToolHandler(const Internal::IosDeviceType &devType, QObject *parent) :
QObject(parent) QObject(parent)
{ {
@@ -762,6 +877,11 @@ void IosToolHandler::stop()
d->stop(-1); d->stop(-1);
} }
void IosToolHandler::debuggerStateChanged(int state)
{
d->debuggerStateChanged((Debugger::DebuggerState)state);
}
void IosToolHandler::requestTransferApp(const QString &bundlePath, const QString &deviceId, void IosToolHandler::requestTransferApp(const QString &bundlePath, const QString &deviceId,
int timeout) int timeout)
{ {
@@ -784,24 +904,4 @@ bool IosToolHandler::isRunning()
return d->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 } // namespace Ios

View File

@@ -33,7 +33,6 @@
#include <QStringList> #include <QStringList>
#include <QProcess> #include <QProcess>
namespace Ios { namespace Ios {
namespace Internal { namespace Internal {
class IosToolHandlerPrivate; class IosToolHandlerPrivate;
@@ -56,7 +55,6 @@ public:
}; };
static QString iosDeviceToolPath(); static QString iosDeviceToolPath();
static QString iosSimulatorToolPath();
explicit IosToolHandler(const Internal::IosDeviceType &type, QObject *parent = 0); explicit IosToolHandler(const Internal::IosDeviceType &type, QObject *parent = 0);
~IosToolHandler(); ~IosToolHandler();
@@ -66,6 +64,7 @@ public:
void requestDeviceInfo(const QString &deviceId, int timeout = 1000); void requestDeviceInfo(const QString &deviceId, int timeout = 1000);
bool isRunning(); bool isRunning();
void stop(); void stop();
void debuggerStateChanged(int state);
signals: signals:
void isTransferringApp(Ios::IosToolHandler *handler, const QString &bundlePath, void isTransferringApp(Ios::IosToolHandler *handler, const QString &bundlePath,
@@ -85,11 +84,10 @@ signals:
void errorMsg(Ios::IosToolHandler *handler, const QString &msg); void errorMsg(Ios::IosToolHandler *handler, const QString &msg);
void toolExited(Ios::IosToolHandler *handler, int code); void toolExited(Ios::IosToolHandler *handler, int code);
void finished(Ios::IosToolHandler *handler); void finished(Ios::IosToolHandler *handler);
private:
void subprocessError(QProcess::ProcessError error); protected:
void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void subprocessHasData();
void killProcess(); void killProcess();
private: private:
friend class Ios::Internal::IosToolHandlerPrivate; friend class Ios::Internal::IosToolHandlerPrivate;
Ios::Internal::IosToolHandlerPrivate *d; Ios::Internal::IosToolHandlerPrivate *d;

View 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"

View 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

View File

@@ -77,7 +77,7 @@ exists(../shared/qbs/qbs.pro)|!isEmpty(QBS_INSTALL_DIR): \
isEmpty(LLVM_INSTALL_DIR):LLVM_INSTALL_DIR=$$(LLVM_INSTALL_DIR) isEmpty(LLVM_INSTALL_DIR):LLVM_INSTALL_DIR=$$(LLVM_INSTALL_DIR)
exists($$LLVM_INSTALL_DIR) { exists($$LLVM_INSTALL_DIR) {
SUBDIRS += clangcodemodel SUBDIRS += clangcodemodel
SUBDIRS += clangrefactoring # SUBDIRS += clangrefactoring
} else { } else {
warning("Set LLVM_INSTALL_DIR to build the Clang Code Model. " \ warning("Set LLVM_INSTALL_DIR to build the Clang Code Model. " \
"For details, see doc/src/editors/creator-clang-codemodel.qdoc.") "For details, see doc/src/editors/creator-clang-codemodel.qdoc.")

View File

@@ -208,7 +208,16 @@ Utils::FileName AbstractMsvcToolChain::compilerCommand() const
{ {
Utils::Environment env = Utils::Environment::systemEnvironment(); Utils::Environment env = Utils::Environment::systemEnvironment();
addToEnvironment(env); 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 IOutputParser *AbstractMsvcToolChain::outputParser() const

View File

@@ -1061,6 +1061,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
connect(ICore::instance(), &ICore::saveSettingsRequested, connect(ICore::instance(), &ICore::saveSettingsRequested,
dd, &ProjectExplorerPluginPrivate::savePersistentSettings); dd, &ProjectExplorerPluginPrivate::savePersistentSettings);
connect(EditorManager::instance(), &EditorManager::autoSaved, this, [this] {
if (!dd->m_shuttingDown && !SessionManager::loadingSession())
SessionManager::save();
});
addAutoReleasedObject(new ProjectTreeWidgetFactory); addAutoReleasedObject(new ProjectTreeWidgetFactory);
addAutoReleasedObject(new FolderNavigationWidgetFactory); addAutoReleasedObject(new FolderNavigationWidgetFactory);
@@ -1518,11 +1522,7 @@ void ProjectExplorerPlugin::openNewProjectDialog()
void ProjectExplorerPluginPrivate::showSessionManager() void ProjectExplorerPluginPrivate::showSessionManager()
{ {
if (SessionManager::isDefaultVirgin()) {
// do not save new virgin default sessions
} else {
SessionManager::save(); SessionManager::save();
}
SessionDialog sessionDialog(ICore::mainWindow()); SessionDialog sessionDialog(ICore::mainWindow());
sessionDialog.setAutoLoadSession(dd->m_projectExplorerSettings.autorestoreLastSession); sessionDialog.setAutoLoadSession(dd->m_projectExplorerSettings.autorestoreLastSession);
sessionDialog.exec(); sessionDialog.exec();
@@ -1551,12 +1551,8 @@ void ProjectExplorerPluginPrivate::savePersistentSettings()
foreach (Project *pro, SessionManager::projects()) foreach (Project *pro, SessionManager::projects())
pro->saveSettings(); pro->saveSettings();
if (SessionManager::isDefaultVirgin()) {
// do not save new virgin default sessions
} else {
SessionManager::save(); SessionManager::save();
} }
}
QSettings *s = ICore::settings(); QSettings *s = ICore::settings();
s->setValue(QLatin1String("ProjectExplorer/StartupSession"), SessionManager::activeSession()); s->setValue(QLatin1String("ProjectExplorer/StartupSession"), SessionManager::activeSession());

View File

@@ -50,6 +50,7 @@
#include <QComboBox> #include <QComboBox>
#include <QDockWidget> #include <QDockWidget>
#include <QHeaderView> #include <QHeaderView>
#include <QLabel>
#include <QMenu> #include <QMenu>
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QTimer> #include <QTimer>
@@ -234,6 +235,11 @@ public:
{ {
Q_UNUSED(column) Q_UNUSED(column)
if (role == ItemUpdatedFromBelowRole) {
announceChange();
return true;
}
if (role == ItemDeactivatedFromBelowRole) { if (role == ItemDeactivatedFromBelowRole) {
announceChange(); announceChange();
return true; return true;
@@ -375,16 +381,13 @@ public:
this, &SelectorModel::openContextMenu); this, &SelectorModel::openContextMenu);
} }
void announceChange()
{
m_changeListener(m_projectsModel.rootItem()->childAt(0)->data(0, PanelWidgetRole).value<QWidget *>());
}
void updatePanel() 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()->clear();
m_selectorTree->selectionModel()->select(activeIndex, QItemSelectionModel::Select); m_selectorTree->selectionModel()->select(activeIndex, QItemSelectionModel::Select);
} }
@@ -481,9 +484,16 @@ ProjectWindow::ProjectWindow()
selectorView->setWindowTitle(tr("Project Selector")); selectorView->setWindowTitle(tr("Project Selector"));
selectorView->setAutoFillBackground(true); 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; auto innerLayout = new QVBoxLayout;
innerLayout->setSpacing(10); innerLayout->setSpacing(10);
innerLayout->setContentsMargins(14, innerLayout->spacing(), 14, 0); innerLayout->setContentsMargins(14, innerLayout->spacing(), 14, 0);
innerLayout->addWidget(activeLabel);
innerLayout->addWidget(selectorModel->m_projectSelection); innerLayout->addWidget(selectorModel->m_projectSelection);
innerLayout->addWidget(selectorModel->m_selectorTree); innerLayout->addWidget(selectorModel->m_selectorTree);

View File

@@ -42,6 +42,7 @@ enum {
ItemActivatedFromBelowRole, // A subitem gots activated and gives us the opportunity to adjust ItemActivatedFromBelowRole, // A subitem gots activated and gives us the opportunity to adjust
ItemActivatedFromAboveRole, // A parent item gots activated and makes us its active child. ItemActivatedFromAboveRole, // A parent item gots activated and makes us its active child.
ItemDeactivatedFromBelowRole, // A subitem got deactivated and gives us the opportunity to adjust 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 ActiveItemRole, // The index of the currently selected item in the tree view
PanelWidgetRole // This item's widget to be shown as central widget. PanelWidgetRole // This item's widget to be shown as central widget.
}; };

View File

@@ -408,6 +408,10 @@ bool SessionManager::loadingSession()
bool SessionManager::save() bool SessionManager::save()
{ {
// do not save new virgin default sessions
if (isDefaultVirgin())
return true;
emit m_instance->aboutToSaveSession(); emit m_instance->aboutToSaveSession();
if (!d->m_writer || d->m_writer->fileName() != sessionNameToFileName(d->m_sessionName)) { 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 // Allow everyone to set something in the session and before saving
emit m_instance->aboutToUnloadSession(d->m_sessionName); emit m_instance->aboutToUnloadSession(d->m_sessionName);
if (!isDefaultVirgin()) {
if (!save()) { if (!save()) {
d->m_loadingSession = false; d->m_loadingSession = false;
return false; return false;
} }
}
// Clean up // Clean up
if (!EditorManager::closeAllEditors()) { if (!EditorManager::closeAllEditors()) {

View File

@@ -212,6 +212,7 @@ public:
void handleRemovedKit(Kit *kit); void handleRemovedKit(Kit *kit);
void handleAddedKit(Kit *kit); void handleAddedKit(Kit *kit);
void handleUpdatedKit(Kit *kit);
void handleTargetAdded(Target *target); void handleTargetAdded(Target *target);
void handleTargetRemoved(Target *target); void handleTargetRemoved(Target *target);
@@ -755,6 +756,8 @@ TargetGroupItemPrivate::TargetGroupItemPrivate(TargetGroupItem *q, Project *proj
this, &TargetGroupItemPrivate::handleAddedKit); this, &TargetGroupItemPrivate::handleAddedKit);
connect(KitManager::instance(), &KitManager::kitRemoved, connect(KitManager::instance(), &KitManager::kitRemoved,
this, &TargetGroupItemPrivate::handleRemovedKit); this, &TargetGroupItemPrivate::handleRemovedKit);
connect(KitManager::instance(), &KitManager::kitUpdated,
this, &TargetGroupItemPrivate::handleUpdatedKit);
rebuildContents(); rebuildContents();
} }
@@ -789,7 +792,7 @@ QVariant TargetGroupItem::data(int column, int role) const
bool TargetGroupItem::setData(int column, const QVariant &data, int role) bool TargetGroupItem::setData(int column, const QVariant &data, int role)
{ {
Q_UNUSED(data) Q_UNUSED(data)
if (role == ItemActivatedFromBelowRole) { if (role == ItemActivatedFromBelowRole || role == ItemUpdatedFromBelowRole) {
// Bubble up to trigger setting the active project. // Bubble up to trigger setting the active project.
parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), role); parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), role);
return true; return true;
@@ -823,8 +826,15 @@ void TargetGroupItemPrivate::handleRemovedKit(Kit *kit)
rebuildContents(); rebuildContents();
} }
void TargetGroupItemPrivate::handleUpdatedKit(Kit *kit)
{
Q_UNUSED(kit);
rebuildContents();
}
void TargetGroupItemPrivate::handleAddedKit(Kit *kit) void TargetGroupItemPrivate::handleAddedKit(Kit *kit)
{ {
if (m_project->supportsKit(kit))
q->appendChild(new TargetItem(m_project, kit->id())); q->appendChild(new TargetItem(m_project, kit->id()));
} }
@@ -843,8 +853,14 @@ void TargetGroupItemPrivate::rebuildContents()
{ {
q->removeChildren(); 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())); 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) void TargetGroupItemPrivate::handleTargetAdded(Target *target)

View File

@@ -1477,7 +1477,9 @@ void QmakeProject::collectLibraryData(const QmakeProFileNode *node, DeploymentDa
destDir.append(QLatin1Char('/')).append(ti.target) destDir.append(QLatin1Char('/')).append(ti.target)
.append(QLatin1String(".framework")); .append(QLatin1String(".framework"));
} else { } else {
if (!(isPlugin && config.contains(QLatin1String("no_plugin_name_prefix"))))
targetFileName.prepend(QLatin1String("lib")); targetFileName.prepend(QLatin1String("lib"));
if (!isPlugin) { if (!isPlugin) {
targetFileName += QLatin1Char('.'); targetFileName += QLatin1Char('.');
const QString version = node->singleVariableValue(VersionVar); const QString version = node->singleVariableValue(VersionVar);
@@ -1496,7 +1498,9 @@ void QmakeProject::collectLibraryData(const QmakeProFileNode *node, DeploymentDa
case Abi::LinuxOS: case Abi::LinuxOS:
case Abi::BsdOS: case Abi::BsdOS:
case Abi::UnixOS: case Abi::UnixOS:
if (!(isPlugin && config.contains(QLatin1String("no_plugin_name_prefix"))))
targetFileName.prepend(QLatin1String("lib")); targetFileName.prepend(QLatin1String("lib"));
targetFileName += QLatin1Char('.'); targetFileName += QLatin1Char('.');
if (isStatic) { if (isStatic) {
targetFileName += QLatin1Char('a'); targetFileName += QLatin1Char('a');

View File

@@ -63,7 +63,7 @@ static CrumbleBarInfo createCrumbleBarInfoFromModelNode(const ModelNode &modelNo
{ {
CrumbleBarInfo crumbleBarInfo; CrumbleBarInfo crumbleBarInfo;
crumbleBarInfo.displayName = componentIdForModelNode(modelNode); crumbleBarInfo.displayName = componentIdForModelNode(modelNode);
crumbleBarInfo.fileName = currentDesignDocument()->textEditor()->document()->filePath().toString(); crumbleBarInfo.fileName = currentDesignDocument()->textEditor()->document()->filePath();
crumbleBarInfo.modelNode = modelNode; crumbleBarInfo.modelNode = modelNode;
return crumbleBarInfo; return crumbleBarInfo;
@@ -87,7 +87,7 @@ CrumbleBar::~CrumbleBar()
delete m_crumblePath; delete m_crumblePath;
} }
void CrumbleBar::pushFile(const QString &fileName) void CrumbleBar::pushFile(const Utils::FileName &fileName)
{ {
if (m_isInternalCalled == false) { if (m_isInternalCalled == false) {
crumblePath()->clear(); crumblePath()->clear();
@@ -102,7 +102,7 @@ void CrumbleBar::pushFile(const QString &fileName)
CrumbleBarInfo crumbleBarInfo; CrumbleBarInfo crumbleBarInfo;
crumbleBarInfo.fileName = fileName; crumbleBarInfo.fileName = fileName;
crumblePath()->pushElement(fileName.split(QLatin1String("/")).last(), QVariant::fromValue(crumbleBarInfo)); crumblePath()->pushElement(fileName.fileName(), QVariant::fromValue(crumbleBarInfo));
m_isInternalCalled = false; m_isInternalCalled = false;
@@ -171,7 +171,7 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data)
m_isInternalCalled = true; m_isInternalCalled = true;
if (!clickedCrumbleBarInfo.modelNode.isValid() if (!clickedCrumbleBarInfo.modelNode.isValid()
&& Utils::FileName::fromString(clickedCrumbleBarInfo.fileName) == currentDesignDocument()->fileName()) { && clickedCrumbleBarInfo.fileName == currentDesignDocument()->fileName()) {
nextFileIsCalledInternally(); nextFileIsCalledInternally();
currentDesignDocument()->changeToDocumentModel(); currentDesignDocument()->changeToDocumentModel();
QmlDesignerPlugin::instance()->viewManager().setComponentViewToMaster(); QmlDesignerPlugin::instance()->viewManager().setComponentViewToMaster();
@@ -179,8 +179,8 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data)
showSaveDialog(); showSaveDialog();
crumblePath()->popElement(); crumblePath()->popElement();
nextFileIsCalledInternally(); nextFileIsCalledInternally();
Core::EditorManager::openEditor(clickedCrumbleBarInfo.fileName, Core::Id(), Core::EditorManager::openEditor(clickedCrumbleBarInfo.fileName.toString(),
Core::EditorManager::DoNotMakeVisible); Core::Id(), Core::EditorManager::DoNotMakeVisible);
if (clickedCrumbleBarInfo.modelNode.isValid()) { if (clickedCrumbleBarInfo.modelNode.isValid()) {
currentDesignDocument()->changeToSubComponent(clickedCrumbleBarInfo.modelNode); currentDesignDocument()->changeToSubComponent(clickedCrumbleBarInfo.modelNode);
QmlDesignerPlugin::instance()->viewManager().setComponentNode(clickedCrumbleBarInfo.modelNode); QmlDesignerPlugin::instance()->viewManager().setComponentNode(clickedCrumbleBarInfo.modelNode);

View File

@@ -27,6 +27,7 @@
#include <QObject> #include <QObject>
#include <utils/crumblepath.h> #include <utils/crumblepath.h>
#include <utils/fileutils.h>
#include <modelnode.h> #include <modelnode.h>
namespace QmlDesigner { namespace QmlDesigner {
@@ -38,7 +39,7 @@ public:
explicit CrumbleBar(QObject *parent = 0); explicit CrumbleBar(QObject *parent = 0);
~CrumbleBar(); ~CrumbleBar();
void pushFile(const QString &fileName); void pushFile(const Utils::FileName &fileName);
void pushInFileComponent(const ModelNode &modelNode); void pushInFileComponent(const ModelNode &modelNode);
void nextFileIsCalledInternally(); void nextFileIsCalledInternally();
@@ -59,7 +60,7 @@ private:
class CrumbleBarInfo { class CrumbleBarInfo {
public: public:
QString fileName; Utils::FileName fileName;
QString displayName; QString displayName;
ModelNode modelNode; ModelNode modelNode;
}; };

View File

@@ -71,10 +71,10 @@ static bool importLess(const Import &firstImport, const Import &secondImport)
return false; return false;
if (firstImport.isLibraryImport() && secondImport.isFileImport()) if (firstImport.isLibraryImport() && secondImport.isFileImport())
return true; return false;
if (firstImport.isFileImport() && secondImport.isLibraryImport()) if (firstImport.isFileImport() && secondImport.isLibraryImport())
return false; return true;
if (firstImport.isFileImport() && secondImport.isFileImport()) if (firstImport.isFileImport() && secondImport.isFileImport())
return QString::localeAwareCompare(firstImport.file(), secondImport.file()) < 0; return QString::localeAwareCompare(firstImport.file(), secondImport.file()) < 0;

View File

@@ -191,7 +191,9 @@ void ComponentView::searchForComponentAndAddToList(const ModelNode &node)
bool masterNotAdded = true; bool masterNotAdded = true;
foreach (const ModelNode &node, node.allSubModelNodesAndThisNode()) { foreach (const ModelNode &node, node.allSubModelNodesAndThisNode()) {
if (node.nodeSourceType() == ModelNode::NodeWithComponentSource) { if (node.nodeSourceType() == ModelNode::NodeWithComponentSource
|| (node.hasParentProperty()
&& !node.parentProperty().isDefaultProperty())) {
if (masterNotAdded) { if (masterNotAdded) {
masterNotAdded = true; masterNotAdded = true;
addMasterDocument(); addMasterDocument();
@@ -200,9 +202,6 @@ void ComponentView::searchForComponentAndAddToList(const ModelNode &node)
if (!hasEntryForNode(node)) { if (!hasEntryForNode(node)) {
QString description = descriptionForNode(node); QString description = descriptionForNode(node);
QStandardItem *item = new QStandardItem(description); QStandardItem *item = new QStandardItem(description);
item->setData(QVariant::fromValue(node.internalId()), ModelNodeRole); item->setData(QVariant::fromValue(node.internalId()), ModelNodeRole);
item->setEditable(false); item->setEditable(false);

View File

@@ -321,7 +321,7 @@ void DesignDocument::changeToMaster()
if (m_inFileComponentModel) if (m_inFileComponentModel)
changeToDocumentModel(); changeToDocumentModel();
QmlDesignerPlugin::instance()->viewManager().pushFileOnCrumbleBar(fileName().toString()); QmlDesignerPlugin::instance()->viewManager().pushFileOnCrumbleBar(fileName());
QmlDesignerPlugin::instance()->viewManager().setComponentNode(rootModelNode()); QmlDesignerPlugin::instance()->viewManager().setComponentNode(rootModelNode());
} }

Some files were not shown because too many files have changed in this diff Show More