Merge remote-tracking branch 'origin/3.6'

Change-Id: I68512c775ed25b51c8b0abe1818c9c7c5955874c
This commit is contained in:
Eike Ziller
2015-10-30 16:07:56 +01:00
95 changed files with 1696 additions and 860 deletions

104
dist/changes-3.5.0.md vendored
View File

@@ -193,55 +193,55 @@ BareMetal
* Fixed processing of additional OpenOCD arguments * Fixed processing of additional OpenOCD arguments
Credits for these changes go to: Credits for these changes go to:
Alessandro Portale Alessandro Portale
André Pönitz André Pönitz
Alexander Drozdov Alexander Drozdov
Alexander Izmailov Alexander Izmailov
Arnold Dumas Arnold Dumas
Benjamin Zeller Benjamin Zeller
BogDan Vatra BogDan Vatra
Christian Kandeler Christian Kandeler
Christian Stenger Christian Stenger
Cristian Adam Cristian Adam
Daniel Teske Daniel Teske
David Schulz David Schulz
Denis Kormalev Denis Kormalev
Eike Ziller Eike Ziller
Erik Verbruggen Erik Verbruggen
Finn Brudal Finn Brudal
Friedemann Kleint Friedemann Kleint
Hugues Delorme Hugues Delorme
Jack Andersen Jack Andersen
Jarek Kobus Jarek Kobus
Jochen Becher Jochen Becher
Jörg Bornemann Jörg Bornemann
Johannes Lorenz Johannes Lorenz
Kai Köhne Kai Köhne
Knut Petter Svendsen Knut Petter Svendsen
Kudryavtsev Alexander Kudryavtsev Alexander
Leena Miettinen Leena Miettinen
Libor Tomsik Libor Tomsik
Lorenz Haas Lorenz Haas
Lukas Holecek Lukas Holecek
Marcel Krems Marcel Krems
Marco Benelli Marco Benelli
Marco Bubke Marco Bubke
Montel Laurent Montel Laurent
Nikita Baryshnikov Nikita Baryshnikov
Nikita Kniazev Nikita Kniazev
Nikolai Kosjar Nikolai Kosjar
Olivier Goffart Olivier Goffart
Orgad Shaneh Orgad Shaneh
Ray Donnelly Ray Donnelly
Robert Löhning Robert Löhning
Stanislav Ionascu Stanislav Ionascu
Sune Vuorela Sune Vuorela
Takumi ASAKI Takumi ASAKI
Tasuku Suzuki Tasuku Suzuki
Thiago Macieira Thiago Macieira
Thomas Hartmann Thomas Hartmann
Thorben Kroeger Thorben Kroeger
Tim Jenssen Tim Jenssen
Tobias Hunger Tobias Hunger
Ulf Hermann Ulf Hermann

45
dist/changes-3.6.0.md vendored
View File

@@ -51,7 +51,7 @@ C++ Support
* Added support for `noexcept` * Added support for `noexcept`
* Clang code model * Clang code model
* Added diagnostic messages to editors * Added more diagnostic messages to editors
* Added Clang's Fix-its to refactoring actions (QTCREATORBUG-14868) * Added Clang's Fix-its to refactoring actions (QTCREATORBUG-14868)
Debugging Debugging
@@ -125,3 +125,46 @@ Remote Linux
ECDSA user keys, and ECDSA key creation ECDSA user keys, and ECDSA key creation
* Fixed environment and working directory for Valgrind analyzer * Fixed environment and working directory for Valgrind analyzer
Credits for these changes go to:
Aleix Pol
Alessandro Portale
Alexander Drozdov
Andre Hartmann
André Pönitz
Benjamin Zeller
BogDan Vatra
Christian Kandeler
Christian Stenger
Christian Strømme
Claus Steuer
Cristian Adam
Daniel Teske
David Schulz
Eike Ziller
Jake Petroules
Jakub Golebiewski
Jan Dalheimer
Jarek Kobus
Jean Gressmann
Jochen Becher
Leena Miettinen
Lorenz Haas
Marco Bubke
Maurice Kalinowski
Mitch Curtis
Montel Laurent
Niels Weber
Nikita Baryshnikov
Nikolai Kosjar
Oliver Wolff
Orgad Shaneh
Oswald Buddenhagen
Robert Loehning
Sze Howe Koh
Thiago Macieira
Thomas Hartmann
Thorbjørn Lindeijer
Tim Jenssen
Tobias Hunger
Ulf Hermann
Vladyslav Gapchych

View File

@@ -23,6 +23,7 @@ indexes += $QDOC_INDEX_DIR/qtwidgets/qtwidgets.index \
$QDOC_INDEX_DIR/qtgui/qtgui.index \ $QDOC_INDEX_DIR/qtgui/qtgui.index \
$QDOC_INDEX_DIR/qthelp/qthelp.index \ $QDOC_INDEX_DIR/qthelp/qthelp.index \
$QDOC_INDEX_DIR/qtquickcontrols/qtquickcontrols.index \ $QDOC_INDEX_DIR/qtquickcontrols/qtquickcontrols.index \
$QDOC_INDEX_DIR/qtquickextras/qtquickextras.index \
$QDOC_INDEX_DIR/qtquicklayouts/qtquicklayouts.index \ $QDOC_INDEX_DIR/qtquicklayouts/qtquicklayouts.index \
$QDOC_INDEX_DIR/qtlinguist/qtlinguist.index \ $QDOC_INDEX_DIR/qtlinguist/qtlinguist.index \
$QDOC_INDEX_DIR/qtscript/qtscript.index \ $QDOC_INDEX_DIR/qtscript/qtscript.index \

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -1699,6 +1699,13 @@
You can also press \key {Alt+Enter} to open a context menu that contains You can also press \key {Alt+Enter} to open a context menu that contains
refactoring actions available in the current cursor position. refactoring actions available in the current cursor position.
If you use the \l{Parsing C++ Files}{Clang code model} to parse the C++
files, the \l{http://clang.llvm.org/diagnostics.html}{Clang fix-it hints}
that have been integrated into \QC are also available to you. In addition to
the standard ways of activating refactoring actions, you can select the
actions that are applicable on a line in the context menu in the left margin
of the code editor.
\section2 Refactoring C++ Code \section2 Refactoring C++ Code
You can apply the following types of refactoring actions to C++ code: You can apply the following types of refactoring actions to C++ code:
@@ -2312,6 +2319,8 @@
\li QObject::connect() (Qt 4 style) \li QObject::connect() (Qt 4 style)
\endtable \endtable
\section2 Refactoring QML Code \section2 Refactoring QML Code
You can apply the following types of refactoring actions to QML code: You can apply the following types of refactoring actions to QML code:

View File

@@ -185,6 +185,7 @@
\li \l {Creating Buttons} \li \l {Creating Buttons}
\li \l {Creating Scalable Buttons and Borders} \li \l {Creating Scalable Buttons and Borders}
\li \l {Creating Screens} \li \l {Creating Screens}
\li \l {Browsing ISO 7000 Icons}
\li \l {Exporting Designs from Graphics Software} \li \l {Exporting Designs from Graphics Software}
\li \l {Using QML Modules with Plugins} \li \l {Using QML Modules with Plugins}
\endlist \endlist

View File

@@ -69,6 +69,11 @@
Dialogs, and Layouts (available since Qt 5.1) to create screens. You Dialogs, and Layouts (available since Qt 5.1) to create screens. You
can use states and transitions to navigate between screens. can use states and transitions to navigate between screens.
\li \l {Browsing ISO 7000 Icons}
You can add ISO 7000 icons from a library delivered with \QC to Qt
Quick applications and change their color (commercial only).
\li \l {Exporting Designs from Graphics Software} \li \l {Exporting Designs from Graphics Software}
You can export designs from graphics software, such as Adobe You can export designs from graphics software, such as Adobe

View File

@@ -77,6 +77,9 @@
creating classic desktop-style user interfaces using Qt Quick 2.1. You can creating classic desktop-style user interfaces using Qt Quick 2.1. You can
use the Qt Quick Controls Styles to customize Qt Quick Controls. use the Qt Quick Controls Styles to customize Qt Quick Controls.
Some ready-made controls, such as a gauge, dial, status indicator, and
tumbler, are provided by the \l {Qt Quick Extras} module.
The \QC project wizards create Qt Quick applications that use Qt Quick The \QC project wizards create Qt Quick applications that use Qt Quick
Components or Controls. Components or Controls.

View File

@@ -25,7 +25,7 @@
/*! /*!
\contentspage {Qt Creator Manual} \contentspage {Qt Creator Manual}
\previouspage qmldesigner-connections.html \previouspage qtquick-iso-icon-browser.html
\page quick-export-to-qml.html \page quick-export-to-qml.html
\nextpage creator-qml-modules-with-plugins.html \nextpage creator-qml-modules-with-plugins.html

View File

@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*!
\contentspage {Qt Creator Manual}
\previouspage quick-screens.html
\page qtquick-iso-icon-browser.html
\nextpage quick-export-to-qml.html
\title Browsing ISO 7000 Icons
\commercial
You can add icons from an ISO 7000 icon library that is installed with \QC
to Qt Quick applications (commercial only). You can use the
\uicontrol {ISO Icon Browser} to add a \l {Picture} type and select the
icon to use for the type. You can change the default color of the icon.
\image qtcreator-iso-icon-browser.png
\section1 Using ISO Icons in Applications
\list 1
\li Create a new Qt Quick Application or open an application in \QC.
\li Open the Qt Quick UI form in the \uicontrol Design mode.
\li In the \uicontrol Library, select \uicontrol Imports >
\uicontrol {Add Import} > \uicontrol {QtQuick.Extras} to import the
\l {Qt Quick Extras} module.
\li Drag and drop a \uicontrol Picture element from the library to the
canvas.
\li Right-click the picture element and select \uicontrol {Choose Icon}
to open the \uicontrol {ISO Icon Browser}.
\li To find icons, select a criterion for filtering icons and enter a
search string.
\li Select an icon in the list, and then select \uicontrol OK to add
the icon.
\li To view the icon you added, press \key {Ctrl+R} (or \key {Cmd+R})
to run the application.
\li To adjust the icon color, select the icon on the canvas, and then
select \uicontrol {Edit Color} in the context menu.
\endlist
\QC generates a Qt resource file called \c iso-icons.qrc that adds the
icons as a part of your project for delivery with your application.
*/

View File

@@ -27,7 +27,7 @@
\contentspage {Qt Creator Manual} \contentspage {Qt Creator Manual}
\previouspage quick-scalable-image.html \previouspage quick-scalable-image.html
\page quick-screens.html \page quick-screens.html
\nextpage creator-qtquick-designer-extensions.html \nextpage qtquick-iso-icon-browser.html
\title Creating Screens \title Creating Screens

View File

@@ -1,9 +1,9 @@
!isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included") !isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included")
QTCREATOR_PRI_INCLUDED = 1 QTCREATOR_PRI_INCLUDED = 1
QTCREATOR_VERSION = 3.5.81 QTCREATOR_VERSION = 3.5.82
QTCREATOR_COMPAT_VERSION = 3.5.81 QTCREATOR_COMPAT_VERSION = 3.5.82
BINARY_ARTIFACTS_BRANCH = master BINARY_ARTIFACTS_BRANCH = 3.6
# enable c++11 # enable c++11
CONFIG += c++11 CONFIG += c++11

View File

@@ -6,11 +6,11 @@ Project {
property bool withAutotests: qbs.buildVariant === "debug" property bool withAutotests: qbs.buildVariant === "debug"
property string ide_version_major: '3' property string ide_version_major: '3'
property string ide_version_minor: '5' property string ide_version_minor: '5'
property string ide_version_release: '81' property string ide_version_release: '82'
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release
property string ide_compat_version_major: '3' property string ide_compat_version_major: '3'
property string ide_compat_version_minor: '5' property string ide_compat_version_minor: '5'
property string ide_compat_version_release: '81' property string ide_compat_version_release: '82'
property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release
property path ide_source_tree: path property path ide_source_tree: path
property string ide_app_path: qbs.targetOS.contains("osx") ? "" : "bin" property string ide_app_path: qbs.targetOS.contains("osx") ? "" : "bin"

View File

@@ -1269,7 +1269,7 @@ def _qdump__QObject(d, value):
d.putField("keyencoded", Hex2EncodedLatin1) d.putField("keyencoded", Hex2EncodedLatin1)
qq = q.cast(valuesType.pointer().pointer()) qq = q.cast(valuesType.pointer().pointer())
qq = qq.dereference(); qq = qq.dereference();
d.putField("addr", d.cleanAddress(qq)) d.putField("address", d.cleanAddress(qq))
d.putField("exp", "*(%s*)%s" d.putField("exp", "*(%s*)%s"
% (variant, d.cleanAddress(qq))) % (variant, d.cleanAddress(qq)))
t = qdump__QVariant(d, qq) t = qdump__QVariant(d, qq)

View File

@@ -98,12 +98,12 @@
"openAsProject": true "openAsProject": true
}, },
{ {
"source": "../../qmake/qtquickapplication/main.qml", "source": "../../qmake/qtquickapplication/main.qml.tpl",
"target": "%{ProjectDirectory}/%{MainQmlFileName}", "target": "%{ProjectDirectory}/%{MainQmlFileName}",
"openInEditor": true "openInEditor": true
}, },
{ {
"source": "../../qmake/qtquickapplication/MainForm.ui.qml", "source": "../../qmake/qtquickapplication/MainForm.ui.qml.tpl",
"target": "%{ProjectDirectory}/MainForm.ui.qml", "target": "%{ProjectDirectory}/MainForm.ui.qml",
"condition": "%{IsUiFileInUse}" "condition": "%{IsUiFileInUse}"
}, },

View File

@@ -106,12 +106,12 @@
"openAsProject": true "openAsProject": true
}, },
{ {
"source": "../../qmake/qtquickcontrolsapplication/main.qml", "source": "../../qmake/qtquickcontrolsapplication/main.qml.tpl",
"target": "%{ProjectDirectory}/%{MainQmlFileName}", "target": "%{ProjectDirectory}/%{MainQmlFileName}",
"openInEditor": true "openInEditor": true
}, },
{ {
"source": "../../qmake/qtquickcontrolsapplication/MainForm.ui.qml", "source": "../../qmake/qtquickcontrolsapplication/MainForm.ui.qml.tpl",
"target": "%{ProjectDirectory}/MainForm.ui.qml", "target": "%{ProjectDirectory}/MainForm.ui.qml",
"condition": "%{IsUiFileInUse}" "condition": "%{IsUiFileInUse}"
}, },

View File

@@ -13,8 +13,9 @@ defineReplace(findToTranslate) {
SUBKEY = $${ROOTKEY}.$${KEY} SUBKEY = $${ROOTKEY}.$${KEY}
MATCHED = $$find(KEY, ^tr[A-Z]) MATCHED = $$find(KEY, ^tr[A-Z])
!isEmpty(MATCHED) { !isEmpty(MATCHED) {
VALUE = $$eval($${SUBKEY}) VALUE = $$replace($${SUBKEY}, "\\n", "\\n")
OUTPUT += "QCoreApplication(\"ProjectExplorer::JsonWizard\", \"$${VALUE}\");" VALUE ~= s,\",\\\",
OUTPUT += "QT_TRANSLATE_NOOP(\"ProjectExplorer::JsonWizard\", \"$${VALUE}\");"
} }
OUTPUT += $$findToTranslate($${SUBKEY}) OUTPUT += $$findToTranslate($${SUBKEY})
} }
@@ -22,8 +23,7 @@ defineReplace(findToTranslate) {
} }
WIZ_TRANS_FILE_CONT= \ WIZ_TRANS_FILE_CONT= \
"// This file is autogenerated by qmake." \ "// This file is autogenerated by qmake."
"$${LITERAL_HASH}include <QCoreApplication>"
for (FILE, JSONWIZARD_FILES) { for (FILE, JSONWIZARD_FILES) {
exists($$FILE) { exists($$FILE) {

View File

@@ -79,7 +79,7 @@ for(file, files) {
$$v = extract $$v = extract
QMAKE_EXTRA_TARGETS += ts-$$lang QMAKE_EXTRA_TARGETS += ts-$$lang
} }
ts-all.commands = cd $$wd && $$LUPDATE $$sources $$MIME_TR_H $$CUSTOMWIZARD_TR_H $$QMLWIZARD_TR_H $$QTQUICKWIZARD_TR_H $$EXTERNALTOOLS_TR_H -ts $$files ts-all.commands = cd $$wd && $$LUPDATE $$sources $$MIME_TR_H $$CUSTOMWIZARD_TR_H $$JSONWIZARD_TR_H $$QMLWIZARD_TR_H $$QTQUICKWIZARD_TR_H $$EXTERNALTOOLS_TR_H -ts $$files
ts-all.depends = extract ts-all.depends = extract
QMAKE_EXTRA_TARGETS += ts-all QMAKE_EXTRA_TARGETS += ts-all

View File

@@ -13,11 +13,11 @@
<description><![CDATA[Developing Qt applications using C++ and the Qt Widgets module.]]></description> <description><![CDATA[Developing Qt applications using C++ and the Qt Widgets module.]]></description>
<tags>qt,qt creator,qt designer,widgets,c++</tags> <tags>qt,qt creator,qt designer,widgets,c++</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/qtquick.png" difficulty="" docUrl="qthelp://org.qt-project.qtcreator/doc/creator-qml-application.html" projectPath="" name="Creating a Qt Quick Application"> <tutorial imageUrl="images/icons/qtquick.png" difficulty="" docUrl="qthelp://org.qt-project.qtcreator/doc/qtcreator-transitions-example.html" projectPath="" name="Creating a Qt Quick Application">
<description><![CDATA[Using basic QML elements and learning about basic concepts of Qt Quick.]]></description> <description><![CDATA[Using basic QML elements and learning about basic concepts of Qt Quick.]]></description>
<tags>qt creator,qt quick designer,qt quick,qml,states,transitions</tags> <tags>qt creator,qt quick designer,qt quick,qml,states,transitions</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/androidapp.png" difficulty="" docUrl="qthelp://org.qt-project.qtcreator/doc/creator-mobile-app-tutorial.html" projectPath="" name="Creating a Mobile Application"> <tutorial imageUrl="images/icons/androidapp.png" difficulty="" docUrl="qthelp://org.qt-project.qtcreator/doc/qtcreator-accelbubble-example.html" projectPath="" name="Creating a Mobile Application">
<description><![CDATA[Developing Qt Quick applications for Android and iOS devices using Qt Quick Controls.]]></description> <description><![CDATA[Developing Qt Quick applications for Android and iOS devices using Qt Quick Controls.]]></description>
<tags>qt creator,qt quick designer,qml,android</tags> <tags>qt creator,qt quick designer,qml,android</tags>
</tutorial> </tutorial>
@@ -25,10 +25,14 @@
<description><![CDATA[Developing Qt Quick applications using QML and C++.]]></description> <description><![CDATA[Developing Qt Quick applications using QML and C++.]]></description>
<tags>qt quick,qml,c++</tags> <tags>qt quick,qml,c++</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Introduction to Qt Creator" isVideo="true" videoUrl="https://www.youtube.com/watch?v=TEpJLwzdQGs" videoLength="56:22"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Introduction to Qt Creator" isVideo="true" videoUrl="https://www.youtube.com/watch?v=nGFmjOiT22Y" videoLength="50:36">
<description><![CDATA[Getting started with using Qt Creator for cross-platform development.]]></description> <description><![CDATA[Getting started with using Qt Creator for cross-platform development.]]></description>
<tags>qt creator</tags> <tags>qt creator</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Custom Qt Creator Wizards" isVideo="true" videoUrl="https://www.youtube.com/watch?v=Ko3DuCgFamo" videoLength="27:21">
<description><![CDATA[Adding custom file and project creation wizards to Qt Creator.]]></description>
<tags>qt creator,wizard</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Extending Qt Creator Without Writing Code" isVideo="true" videoUrl="http://www.youtube.com/watch?v=DP0lMoLVneY" videoLength="59:49"> <tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Extending Qt Creator Without Writing Code" isVideo="true" videoUrl="http://www.youtube.com/watch?v=DP0lMoLVneY" videoLength="59:49">
<description><![CDATA[Customizing Qt Creator to fit your own or your customers' purposes.]]></description> <description><![CDATA[Customizing Qt Creator to fit your own or your customers' purposes.]]></description>
<tags>qt creator,configuration</tags> <tags>qt creator,configuration</tags>
@@ -37,89 +41,85 @@
<description><![CDATA[Adding plugins to Qt Creator.]]></description> <description><![CDATA[Adding plugins to Qt Creator.]]></description>
<tags>qt creator,plugins</tags> <tags>qt creator,plugins</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Using the QML Profiler" isVideo="true" videoUrl="https://www.youtube.com/watch?v=TiJiF0MOOFc" videoLength="55:12">
<description><![CDATA[Monitoring the performance of a Qt Quick application.]]></description>
<tags>qt quick,qt creator,qml profiler</tags>
</tutorial>
<tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="CPU Usage Analyzer for Device Creation" isVideo="true" videoUrl="https://www.youtube.com/watch?v=G0AbgVHGdXI" videoLength="22:30">
<description><![CDATA[Using the Linux perf tool to generate data for code analysis.]]></description>
<tags>qt creator,cpu usage analyzer,perf</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Targeting Multiple Mobile Platforms with Qt Creator" isVideo="true" videoUrl="http://www.youtube.com/watch?v=jDRup5z2qz0" videoLength="52:38"> <tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Targeting Multiple Mobile Platforms with Qt Creator" isVideo="true" videoUrl="http://www.youtube.com/watch?v=jDRup5z2qz0" videoLength="52:38">
<description><![CDATA[Using Qt Creator to develop a cross-platform application for mobile devices and other small devices.]]></description> <description><![CDATA[Using Qt Creator to develop a cross-platform application for mobile devices and other small devices.]]></description>
<tags>qt creator,qt quick,qml,c++,android,sailfishos</tags> <tags>qt creator,qt quick,qml,c++,android,sailfishos</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Step by Step Qt on Android Tutorial" isVideo="true" videoUrl="http://www.youtube.com/watch?v=yhdi6JONtQo" videoLength="1:02:30"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Effective Multi-Platform Development with Qt Creator, Qbs, and QEMU" isVideo="true" videoUrl="https://www.youtube.com/watch?v=v4glCQt2jE0" videoLength="19:08">
<description><![CDATA[Using Qt Creator, Qbs, and QEMU for application development.]]></description>
<tags>qt creator,qbs,qemu</tags>
</tutorial>
<tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Getting Started with Qt on Android" isVideo="true" videoUrl="https://www.youtube.com/watch?v=FWGUA9RS_ak" videoLength="41:30">
<description><![CDATA[Using Qt Creator to develop a Qt Quick application for Android devices.]]></description> <description><![CDATA[Using Qt Creator to develop a Qt Quick application for Android devices.]]></description>
<tags>qt creator,qt quick,qml,android</tags> <tags>qt creator,android</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Qt for iOS" isVideo="true" videoUrl="http://www.youtube.com/watch?v=HNQpJG2F6ow" videoLength="1:00:48"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Mastering Qt on Android" isVideo="true" videoUrl="https://www.youtube.com/watch?v=xqtoUCjG6GM" videoLength="43:54">
<description><![CDATA[Using Qt Creator to develop a Qt Quick application for iOS that uses sensors and the native camera on the device.]]></description> <description><![CDATA[Using the Qt Android Extras module.]]></description>
<tags>qt creator,qt quick,ios,sensors,camera</tags> <tags>qt,android</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Qt Creator for BareMetal Development" isVideo="true" videoUrl="http://www.youtube.com/watch?v=hrKz63Q_Rf0" videoLength="9:35"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Qt on iOS A to Z" isVideo="true" videoUrl="https://www.youtube.com/watch?v=8A7DPUwIcDg" videoLength="1:05:32">
<description><![CDATA[Using Qt Creator to develop for BareMetal devices.]]></description> <description><![CDATA[Using Qt Creator to develop an application for iOS.]]></description>
<tags>qt creator,ios</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Qt Creator for Bare Metal Development" isVideo="true" videoUrl="http://www.youtube.com/watch?v=hrKz63Q_Rf0" videoLength="9:35">
<description><![CDATA[Using Qt Creator to develop for Bare Metal devices.]]></description>
<tags>qt creator,baremetal</tags> <tags>qt creator,baremetal</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Qt on WinRT" isVideo="true" videoUrl="http://www.youtube.com/watch?v=NubVGd_LcxQ" videoLength="50:01"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Qt and Windows 10" isVideo="true" videoUrl="https://www.youtube.com/watch?v=J9QrPvr-Sg0" videoLength="21:19">
<description><![CDATA[Learning about the experimental Qt on Windows Runtime port.]]></description> <description><![CDATA[Qt support for Windows 10 on desktop, mobile, and embedded devices.]]></description>
<tags>qt,winrt</tags> <tags>qt,Windows 10</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Device Creation with Qt" isVideo="true" videoUrl="https://www.youtube.com/watch?v=RXFnCmlsq3s" videoLength="55:11"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Developing for Windows 10 with Qt" isVideo="true" videoUrl="https://www.youtube.com/watch?v=o5Xdt-j3hkA" videoLength="38:53">
<description><![CDATA[Prototyping and creating your own embedded devices that run Qt applications.]]></description> <description><![CDATA[Using Qt Creator to develop applications for Windows 10.]]></description>
<tags>qt, embedded, device creation,prototype</tags> <tags>qt creator,Windows 10,demo</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Deep Dive into Qt Quick and Qt Quick Controls" isVideo="true" videoUrl="https://www.youtube.com/watch?v=WLoirPcKgg0" videoLength="57:34"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Qt for Device Creation" isVideo="true" videoUrl="https://www.youtube.com/watch?v=nRf1e-AYk0o" videoLength="57:45">
<description><![CDATA[Using Qt Quick Controls to create user interfaces and C++ for the application logic.]]></description> <description><![CDATA[Creating your own embedded devices that run Qt applications.]]></description>
<tags>qt, embedded, device creation</tags>
</tutorial>
<tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Qt Quick Controls Re-Engineered" isVideo="true" videoUrl="https://www.youtube.com/watch?v=FqjabvHSiZk" videoLength="45:34">
<description><![CDATA[Overview of changes planned to Qt Quick Controls.]]></description>
<tags>qt quick,controls</tags> <tags>qt quick,controls</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Adaptable UIs with Qt Quick" isVideo="true" videoUrl="http://www.youtube.com/watch?v=7zlvbHow9Gw" videoLength="46:16"> <tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Adaptable UIs with Qt Quick" isVideo="true" videoUrl="http://www.youtube.com/watch?v=7zlvbHow9Gw" videoLength="46:16">
<description><![CDATA[Implementing adaptable Qt Quick UIs using layouts, bindings, file selectors, and loaders.]]></description> <description><![CDATA[Implementing adaptable Qt Quick UIs using layouts, bindings, file selectors, and loaders.]]></description>
<tags>qt quick,layouts,bindings</tags> <tags>qt quick,layouts,bindings</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Qt Quick and Input Events (Touch, Mouse, Keyboard)" isVideo="true" videoUrl="http://www.youtube.com/watch?v=yTsCkfTAl1s" videoLength="1:07:05"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Qt 3D CAD Demo" isVideo="true" videoUrl="https://www.youtube.com/watch?v=pDgo3EQxtaE" videoLength="10:10">
<description><![CDATA[Handling user input with Qt Quick.]]></description> <description><![CDATA[Creating a CAD application using Qt 3D.]]></description>
<tags>qt quick,qml,input</tags> <tags>qt 3d,demo</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="Building 3D OpenGL Scenes with Qt 5 and QML" isVideo="true" videoUrl="http://www.youtube.com/watch?v=29wCpA0DBZI" videoLength="52:38"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Effective QML" isVideo="true" videoUrl="https://www.youtube.com/watch?v=vzs5VPTf4QQ" videoLength="55:25">
<description><![CDATA[Using QQuickWindow's OpenGL context to render 3D objects.]]></description> <description><![CDATA[Improving your QML code by using tools and by understanding the QML system.]]></description>
<tags>qt quick,qml,3d,opengl</tags> <tags>qml,qml profiler</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Enabling Direct WebGL in Qt Quick 2" isVideo="true" videoUrl="https://www.youtube.com/watch?v=I379HnymiAw" videoLength="51:12"> <tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Qt Widgets and Qt Quick Controls - A Comparison" isVideo="true" videoUrl="https://www.youtube.com/watch?v=-S9ki14ZtIk" videoLength="57:00">
<description><![CDATA[Using Qt Canvas 3D.]]></description>
<tags>qt quick, qt canvas 3d,webgl</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="QML Engine in Depth" isVideo="true" videoUrl="https://www.youtube.com/watch?v=odx7-A9c5Ak" videoLength="1:00:04">
<description><![CDATA[Changes in the QML Engine in Qt 5.4.]]></description>
<tags>qt,qml engine</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays13.png" difficulty="" projectPath="" name="QML Tricks and Treats" isVideo="true" videoUrl="http://www.youtube.com/watch?v=JNDFUHOoPSM" videoLength="56:20">
<description><![CDATA[Structuring an application that combines QML and C++ code, looking up QML language scope and names, creating custom views, handling user input, and styling applications.]]></description>
<tags>qt quick,qml,c++,build,compile,input,styling</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="QtWidgets and QtQuick Controls - A Comparison" isVideo="true" videoUrl="https://www.youtube.com/watch?v=-S9ki14ZtIk" videoLength="57:00">
<description><![CDATA[Comparison of Qt Widgets and Qt Quick Controls.]]></description> <description><![CDATA[Comparison of Qt Widgets and Qt Quick Controls.]]></description>
<tags>qt quick,widgets</tags> <tags>qt quick,widgets</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="QtWebEngine - Learning to Walk" isVideo="true" videoUrl="https://www.youtube.com/watch?v=q_UumdWw1iI" videoLength="51:04"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Qt's Web Offering - An Overview" isVideo="true" videoUrl="https://www.youtube.com/watch?v=XW-oTBCj1JQ" videoLength="23:32">
<description><![CDATA[Introduces the Qt Web Engine technology for desktop and embedded platforms.]]></description> <description><![CDATA[Overview of the Qt modules that provide functions for embedding web content into applications.]]></description>
<tags>qt web engine</tags> <tags>qt webengine</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="QmlWeb - Running Qt Quick Applications on the Web" isVideo="true" videoUrl="https://www.youtube.com/watch?v=q_UumdWw1iI" videoLength="57:05"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Qt WebEngine Taming the Beast" isVideo="true" videoUrl="https://www.youtube.com/watch?v=3CTFxhBc_1I" videoLength="58:23">
<description><![CDATA[Taking QML to the web.]]></description> <description><![CDATA[Using the Qt WebEngine module.]]></description>
<tags>qml,qt quick,web</tags> <tags>qt webengine</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Using the QML Profiler" isVideo="true" videoUrl="https://www.youtube.com/watch?v=TiJiF0MOOFc" videoLength="55:12"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Building Desktop and Embedded UIs with Qt 3D" isVideo="true" videoUrl="https://www.youtube.com/watch?v=QCdti6xmug0" videoLength="47:40">
<description><![CDATA[Monitoring the performance of a Qt Quick application.]]></description> <description><![CDATA[Adding 3D content to Qt applications.]]></description>
<tags>qt quick,qt creator,qml profiler</tags> <tags>qt,qt creator,3d</tags>
</tutorial> </tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Introducing Qt 3D 2.0 (3D Rendering &amp; Visualization)" isVideo="true" videoUrl="https://www.youtube.com/watch?v=WbLBgpancME" videoLength="1:01:24"> <tutorial imageUrl="images/icons/worldsummit15.png" difficulty="" projectPath="" name="Developing for Multiple Screen Resolutions" isVideo="true" videoUrl="https://www.youtube.com/watch?v=nNyhsdX6BsI" videoLength="40:09">
<description><![CDATA[Rendering and visualization in Qt 3D.]]></description> <description><![CDATA[Developing for multiple screen resolutions.]]></description>
<tags>qt,3d</tags> <tags>qt,qt quick,screen resolution</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Rapid UI Prototyping - Better, Faster, Awesome" isVideo="true" videoUrl="https://www.youtube.com/watch?v=j3r_2aaQQIc" videoLength="45:46">
<description><![CDATA[Prototyping with QML and QML Demo.]]></description>
<tags>qt,qml,prototype</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="Analyzing Performance of Qt Quick Applications" isVideo="true" videoUrl="https://www.youtube.com/watch?v=FUMNqX5Q7tw" videoLength="52:01">
<description><![CDATA[Measuring startup time and rendering (in frames per second).]]></description>
<tags>qt quick,qml,qt creator,qml profiler,embedded</tags>
</tutorial>
<tutorial imageUrl="images/icons/ddays14.png" difficulty="" projectPath="" name="A Framework for the Multiscreen World" isVideo="true" videoUrl="https://www.youtube.com/watch?v=qJpuG7fWh98" videoLength="52:36">
<description><![CDATA[Supporting desktop and embedded platforms from the same source.]]></description>
<tags>qt,qml,c++,embedded</tags>
</tutorial> </tutorial>
</tutorials> </tutorials>
</instructionals> </instructionals>

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -696,8 +696,8 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association)
_end_a_cardinality->setEnabled(is_single_selection); _end_a_cardinality->setEnabled(is_single_selection);
} }
if (_end_a_navigable == 0) { if (_end_a_navigable == 0) {
_end_a_navigable = new QCheckBox(_top_widget); _end_a_navigable = new QCheckBox(tr("Navigable"), _top_widget);
_top_layout->addRow(tr("Navigable"), _end_a_navigable); _top_layout->addRow(QString(), _end_a_navigable);
connect(_end_a_navigable, SIGNAL(clicked(bool)), this, SLOT(onAssociationEndANavigableChanged(bool))); connect(_end_a_navigable, SIGNAL(clicked(bool)), this, SLOT(onAssociationEndANavigableChanged(bool)));
} }
if (is_single_selection) { if (is_single_selection) {
@@ -763,8 +763,8 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association)
_end_b_cardinality->setEnabled(is_single_selection); _end_b_cardinality->setEnabled(is_single_selection);
} }
if (_end_b_navigable == 0) { if (_end_b_navigable == 0) {
_end_b_navigable = new QCheckBox(_top_widget); _end_b_navigable = new QCheckBox(tr("Navigable"), _top_widget);
_top_layout->addRow(tr("Navigable"), _end_b_navigable); _top_layout->addRow(QString(), _end_b_navigable);
connect(_end_b_navigable, SIGNAL(clicked(bool)), this, SLOT(onAssociationEndBNavigableChanged(bool))); connect(_end_b_navigable, SIGNAL(clicked(bool)), this, SLOT(onAssociationEndBNavigableChanged(bool)));
} }
if (is_single_selection) { if (is_single_selection) {
@@ -834,8 +834,8 @@ void PropertiesView::MView::visitDObject(const DObject *object)
.arg(object->getRect().bottom())); .arg(object->getRect().bottom()));
#endif #endif
if (_auto_sized_checkbox == 0) { if (_auto_sized_checkbox == 0) {
_auto_sized_checkbox = new QCheckBox(_top_widget); _auto_sized_checkbox = new QCheckBox(tr("Auto sized"), _top_widget);
_top_layout->addRow(tr("Auto sized"), _auto_sized_checkbox); _top_layout->addRow(QString(), _auto_sized_checkbox);
connect(_auto_sized_checkbox, SIGNAL(clicked(bool)), this, SLOT(onAutoSizedChanged(bool))); connect(_auto_sized_checkbox, SIGNAL(clicked(bool)), this, SLOT(onAutoSizedChanged(bool)));
} }
if (!_auto_sized_checkbox->hasFocus()) { if (!_auto_sized_checkbox->hasFocus()) {
@@ -892,8 +892,8 @@ void PropertiesView::MView::visitDObject(const DObject *object)
} }
} }
if (_visual_emphasized_checkbox == 0) { if (_visual_emphasized_checkbox == 0) {
_visual_emphasized_checkbox = new QCheckBox(_top_widget); _visual_emphasized_checkbox = new QCheckBox(tr("Emphasized"), _top_widget);
_top_layout->addRow(tr("Emphasized"), _visual_emphasized_checkbox); _top_layout->addRow(QString(), _visual_emphasized_checkbox);
connect(_visual_emphasized_checkbox, SIGNAL(clicked(bool)), this, SLOT(onVisualEmphasizedChanged(bool))); connect(_visual_emphasized_checkbox, SIGNAL(clicked(bool)), this, SLOT(onVisualEmphasizedChanged(bool)));
} }
if (!_visual_emphasized_checkbox->hasFocus()) { if (!_visual_emphasized_checkbox->hasFocus()) {
@@ -957,8 +957,8 @@ void PropertiesView::MView::visitDClass(const DClass *klass)
} }
} }
if (_show_all_members_checkbox == 0) { if (_show_all_members_checkbox == 0) {
_show_all_members_checkbox = new QCheckBox(_top_widget); _show_all_members_checkbox = new QCheckBox(tr("Show members"), _top_widget);
_top_layout->addRow(tr("Show members"), _show_all_members_checkbox); _top_layout->addRow(QString(), _show_all_members_checkbox);
connect(_show_all_members_checkbox, SIGNAL(clicked(bool)), this, SLOT(onShowAllMembersChanged(bool))); connect(_show_all_members_checkbox, SIGNAL(clicked(bool)), this, SLOT(onShowAllMembersChanged(bool)));
} }
if (!_show_all_members_checkbox->hasFocus()) { if (!_show_all_members_checkbox->hasFocus()) {
@@ -978,8 +978,8 @@ void PropertiesView::MView::visitDComponent(const DComponent *component)
setStyleElementType(StyleEngine::TYPE_COMPONENT); setStyleElementType(StyleEngine::TYPE_COMPONENT);
visitDObject(component); visitDObject(component);
if (_plain_shape_checkbox == 0) { if (_plain_shape_checkbox == 0) {
_plain_shape_checkbox = new QCheckBox(_top_widget); _plain_shape_checkbox = new QCheckBox(tr("Plain shape"), _top_widget);
_top_layout->addRow(tr("Plain shape"), _plain_shape_checkbox); _top_layout->addRow(QString(), _plain_shape_checkbox);
connect(_plain_shape_checkbox, SIGNAL(clicked(bool)), this, SLOT(onPlainShapeChanged(bool))); connect(_plain_shape_checkbox, SIGNAL(clicked(bool)), this, SLOT(onPlainShapeChanged(bool)));
} }
if (!_plain_shape_checkbox->hasFocus()) { if (!_plain_shape_checkbox->hasFocus()) {
@@ -1054,8 +1054,8 @@ void PropertiesView::MView::visitDAnnotation(const DAnnotation *annotation)
setTitle<DAnnotation>(_diagram_elements, tr("Annotation"), tr("Annotations")); setTitle<DAnnotation>(_diagram_elements, tr("Annotation"), tr("Annotations"));
visitDElement(annotation); visitDElement(annotation);
if (_annotation_auto_width_checkbox == 0) { if (_annotation_auto_width_checkbox == 0) {
_annotation_auto_width_checkbox = new QCheckBox(_top_widget); _annotation_auto_width_checkbox = new QCheckBox(tr("Auto width"), _top_widget);
_top_layout->addRow(tr("Auto width"), _annotation_auto_width_checkbox); _top_layout->addRow(QString(), _annotation_auto_width_checkbox);
connect(_annotation_auto_width_checkbox, SIGNAL(clicked(bool)), this, SLOT(onAutoWidthChanged(bool))); connect(_annotation_auto_width_checkbox, SIGNAL(clicked(bool)), this, SLOT(onAutoWidthChanged(bool)));
} }
if (!_annotation_auto_width_checkbox->hasFocus()) { if (!_annotation_auto_width_checkbox->hasFocus()) {

View File

@@ -137,12 +137,19 @@ void ProjectSerializer::load(const QString &file_name, Project *project)
#endif #endif
QXmlStreamReader reader(xml_device); QXmlStreamReader reader(xml_device);
qark::QXmlInArchive archive(reader);
archive.beginDocument(); try {
archive >> qark::tag("qmt"); qark::QXmlInArchive archive(reader);
archive >> *project; archive.beginDocument();
archive >> qark::end; archive >> qark::tag("qmt");
archive.endDocument(); archive >> *project;
archive >> qark::end;
archive.endDocument();
} catch (const qark::QXmlInArchive::FileFormatException &) {
throw FileIOException(QStringLiteral("illegal file format"), file_name);
} catch (...) {
throw FileIOException(QStringLiteral("serialization error"), file_name);
}
#ifdef USE_COMPRESSED_FILES #ifdef USE_COMPRESSED_FILES
uncompressor.close(); uncompressor.close();
@@ -155,12 +162,17 @@ void ProjectSerializer::write(QXmlStreamWriter *writer, const Project *project)
writer->setAutoFormatting(true); writer->setAutoFormatting(true);
writer->setAutoFormattingIndent(1); writer->setAutoFormattingIndent(1);
qark::QXmlOutArchive archive(*writer); try {
archive.beginDocument(); qark::QXmlOutArchive archive(*writer);
archive << qark::tag("qmt"); archive.beginDocument();
archive << *project; archive << qark::tag("qmt");
archive << qark::end; archive << *project;
archive.endDocument(); archive << qark::end;
archive.endDocument();
} catch (...) {
throw IOException(QStringLiteral("serialization error"));
}
} }
} }

View File

@@ -548,12 +548,11 @@ protected:
out(ast->typeToken); out(ast->typeToken);
} }
out(" "); out(" ");
out(ast->identifierToken);
if (ast->statement) { if (ast->statement) {
out(ast->identifierToken);
out(": ", ast->colonToken); out(": ", ast->colonToken);
accept(ast->statement); accept(ast->statement);
} else if (ast->binding) { } else if (ast->binding) {
out(": ", ast->colonToken);
accept(ast->binding); accept(ast->binding);
} }
} else { // signal } else { // signal

View File

@@ -280,7 +280,7 @@ extern "C" HRESULT CALLBACK pid(CIDebugClient *client, PCSTR args)
int token; int token;
commandTokens<StringList>(args, &token); commandTokens<StringList>(args, &token);
dprintf("Qt Creator CDB extension version 3.4 %d bit.\n", dprintf("Qt Creator CDB extension version 3.6 %d bit.\n",
sizeof(void *) * 8); sizeof(void *) * 8);
if (const ULONG pid = currentProcessId(client)) if (const ULONG pid = currentProcessId(client))
ExtensionContext::instance().report('R', token, 0, "pid", "%u", pid); ExtensionContext::instance().report('R', token, 0, "pid", "%u", pid);

View File

@@ -1119,7 +1119,7 @@ int SymbolGroupNode::dumpNode(std::ostream &str,
std::wstring value = simpleDumpValue(ctx, &encoding); std::wstring value = simpleDumpValue(ctx, &encoding);
if (addr) { if (addr) {
str << std::hex << std::showbase << ",addr=\"" << addr << '"'; str << std::hex << std::showbase << ",address=\"" << addr << '"';
if (SymbolGroupValue::isPointerType(t)) { if (SymbolGroupValue::isPointerType(t)) {
std::string::size_type pointerPos = value.rfind(L"0x"); std::string::size_type pointerPos = value.rfind(L"0x");
if (pointerPos != std::string::npos) { if (pointerPos != std::string::npos) {
@@ -1602,7 +1602,7 @@ int MapNodeSymbolGroupNode::dump(std::ostream &str, const std::string &visitingF
{ {
SymbolGroupNode::dumpBasicData(str, name(), visitingFullIname); SymbolGroupNode::dumpBasicData(str, name(), visitingFullIname);
if (m_address) if (m_address)
str << ",addr=\"0x" << std::hex << m_address << '"'; str << ",address=\"0x" << std::hex << m_address << '"';
str << ",type=\"" << m_type << "\",valueencoded=\"0\",value=\"\",valueenabled=\"false\"" str << ",type=\"" << m_type << "\",valueencoded=\"0\",value=\"\",valueenabled=\"false\""
",valueeditable=\"false\""; ",valueeditable=\"false\"";
return 2; return 2;

View File

@@ -343,20 +343,20 @@ template<typename C, typename F>
Q_REQUIRED_RESULT Q_REQUIRED_RESULT
C filtered(const C &container, F predicate) C filtered(const C &container, F predicate)
{ {
C out; C out;
std::copy_if(container.begin(), container.end(), std::copy_if(container.begin(), container.end(),
inserter(out), predicate); inserter(out), predicate);
return out; return out;
} }
template<typename C, typename R, typename S> template<typename C, typename R, typename S>
Q_REQUIRED_RESULT Q_REQUIRED_RESULT
C filtered(const C &container, R (S::*predicate)() const) C filtered(const C &container, R (S::*predicate)() const)
{ {
C out; C out;
std::copy_if(container.begin(), container.end(), std::copy_if(container.begin(), container.end(),
inserter(out), std::mem_fn(predicate)); inserter(out), std::mem_fn(predicate));
return out; return out;
} }
////////////////// //////////////////

View File

@@ -1233,21 +1233,15 @@ static bool equalKits(Kit *a, Kit *b)
void AndroidConfigurations::registerNewToolChains() void AndroidConfigurations::registerNewToolChains()
{ {
QList<ToolChain *> existingToolChains = ToolChainManager::toolChains(); const QList<ToolChain *> existingAndroidToolChains
QList<ToolChain *> toolchains = AndroidToolChainFactory::createToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation()); = Utils::filtered(ToolChainManager::toolChains(),
foreach (ToolChain *tc, toolchains) { Utils::equal(&ToolChain::typeId, Core::Id(Constants::ANDROID_TOOLCHAIN_ID)));
bool found = false;
for (int i = 0; i < existingToolChains.count(); ++i) { const QList<ToolChain *> newToolchains
if (*(existingToolChains.at(i)) == *tc) { = AndroidToolChainFactory::autodetectToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation(),
found = true; existingAndroidToolChains);
break; foreach (ToolChain *tc, newToolchains)
}
}
if (found)
delete tc;
else
ToolChainManager::registerToolChain(tc); ToolChainManager::registerToolChain(tc);
}
} }
void AndroidConfigurations::removeOldToolChains() void AndroidConfigurations::removeOldToolChains()

View File

@@ -42,6 +42,7 @@
#include <projectexplorer/toolchainmanager.h> #include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <utils/algorithm.h>
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
@@ -260,8 +261,7 @@ AndroidToolChainFactory::AndroidToolChainFactory()
QList<ToolChain *> AndroidToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) QList<ToolChain *> AndroidToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{ {
Q_UNUSED(alreadyKnown); return autodetectToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation(), alreadyKnown);
return createToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation());
} }
bool AndroidToolChainFactory::canRestore(const QVariantMap &data) bool AndroidToolChainFactory::canRestore(const QVariantMap &data)
@@ -352,11 +352,23 @@ bool AndroidToolChainFactory::versionCompareLess(AndroidToolChain *atc, AndroidT
return versionCompareLess(a, b); return versionCompareLess(a, b);
} }
QList<ToolChain *> AndroidToolChainFactory::createToolChainsForNdk(const FileName &ndkPath) static AndroidToolChain *findToolChain(Utils::FileName &compilerPath, const QList<ToolChain *> &alreadyKnown)
{
return static_cast<AndroidToolChain *>(
Utils::findOrDefault(alreadyKnown, [compilerPath](ToolChain *tc) {
return tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID
&& tc->compilerCommand() == compilerPath;
}));
}
QList<ToolChain *>
AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath,
const QList<ToolChain *> &alreadyKnown)
{ {
QList<ToolChain *> result; QList<ToolChain *> result;
if (ndkPath.isEmpty()) if (ndkPath.isEmpty())
return result; return result;
QRegExp versionRegExp(NDKGccVersionRegExp); QRegExp versionRegExp(NDKGccVersionRegExp);
FileName path = ndkPath; FileName path = ndkPath;
QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(),
@@ -373,13 +385,16 @@ QList<ToolChain *> AndroidToolChainFactory::createToolChainsForNdk(const FileNam
Abi abi = AndroidConfig::abiForToolChainPrefix(platform); Abi abi = AndroidConfig::abiForToolChainPrefix(platform);
if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
continue; continue;
AndroidToolChain *tc = new AndroidToolChain(abi, version, ToolChain::AutoDetection);
FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, version); FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, version);
tc->resetToolChain(compilerPath);
AndroidToolChain *tc = findToolChain(compilerPath, alreadyKnown);
if (!tc) {
tc = new AndroidToolChain(abi, version, ToolChain::AutoDetection);
tc->resetToolChain(compilerPath);
}
result.append(tc); result.append(tc);
QHash<Abi, AndroidToolChain *>::const_iterator it auto it = newestToolChainForArch.constFind(abi);
= newestToolChainForArch.constFind(abi);
if (it == newestToolChainForArch.constEnd()) if (it == newestToolChainForArch.constEnd())
newestToolChainForArch.insert(abi, tc); newestToolChainForArch.insert(abi, tc);
else if (versionCompareLess(it.value(), tc)) else if (versionCompareLess(it.value(), tc))
@@ -388,8 +403,7 @@ QList<ToolChain *> AndroidToolChainFactory::createToolChainsForNdk(const FileNam
foreach (ToolChain *tc, result) { foreach (ToolChain *tc, result) {
AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc); AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
if (newestToolChainForArch.value(atc->targetAbi()) != atc) atc->setSecondaryToolChain(newestToolChainForArch.value(atc->targetAbi()) != atc);
atc->setSecondaryToolChain(true);
} }
return result; return result;

View File

@@ -113,7 +113,9 @@ public:
QString version; QString version;
}; };
static QList<ProjectExplorer::ToolChain *> createToolChainsForNdk(const Utils::FileName &ndkPath); static QList<ProjectExplorer::ToolChain *>
autodetectToolChainsForNdk(const Utils::FileName &ndkPath,
const QList<ProjectExplorer::ToolChain *> &alreadyKnown);
static QList<AndroidToolChainInformation> toolchainPathsForNdk(const Utils::FileName &ndkPath); static QList<AndroidToolChainInformation> toolchainPathsForNdk(const Utils::FileName &ndkPath);
static QList<int> versionNumberFromString(const QString &version); static QList<int> versionNumberFromString(const QString &version);

View File

@@ -61,13 +61,14 @@ namespace Internal {
const char USE_NINJA_KEY[] = "CMakeProjectManager.CMakeBuildConfiguration.UseNinja"; const char USE_NINJA_KEY[] = "CMakeProjectManager.CMakeBuildConfiguration.UseNinja";
const char INITIAL_ARGUMENTS[] = "CMakeProjectManager.CMakeBuildConfiguration.InitialArgument"; const char INITIAL_ARGUMENTS[] = "CMakeProjectManager.CMakeBuildConfiguration.InitialArgument";
static FileName shadowBuildDirectory(const FileName &projectFilePath, const Kit *k, const QString &bcName) static FileName shadowBuildDirectory(const FileName &projectFilePath, const Kit *k,
const QString &bcName, BuildConfiguration::BuildType buildType)
{ {
if (projectFilePath.isEmpty()) if (projectFilePath.isEmpty())
return FileName(); return FileName();
const QString projectName = projectFilePath.parentDir().fileName(); const QString projectName = projectFilePath.parentDir().fileName();
ProjectMacroExpander expander(projectName, k, bcName); ProjectMacroExpander expander(projectName, k, bcName, buildType);
QDir projectDir = QDir(Project::projectDirectory(projectFilePath).toString()); QDir projectDir = QDir(Project::projectDirectory(projectFilePath).toString());
QString buildPath = expander.expand(Core::DocumentManager::buildDirectory()); QString buildPath = expander.expand(Core::DocumentManager::buildDirectory());
return FileName::fromUserInput(projectDir.absoluteFilePath(buildPath)); return FileName::fromUserInput(projectDir.absoluteFilePath(buildPath));
@@ -79,7 +80,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent
CMakeProject *project = static_cast<CMakeProject *>(parent->project()); CMakeProject *project = static_cast<CMakeProject *>(parent->project());
setBuildDirectory(shadowBuildDirectory(project->projectFilePath(), setBuildDirectory(shadowBuildDirectory(project->projectFilePath(),
parent->kit(), parent->kit(),
displayName())); displayName(), BuildConfiguration::Unknown));
} }
CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent, CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent,
@@ -202,7 +203,8 @@ QList<ProjectExplorer::BuildInfo *> CMakeBuildConfigurationFactory::availableSet
} else { } else {
info->displayName = info->typeName; info->displayName = info->typeName;
} }
info->buildDirectory = shadowBuildDirectory(projectPathName, k, info->displayName); info->buildDirectory
= shadowBuildDirectory(projectPathName, k, info->displayName, info->buildType);
result << info; result << info;
} }
return result; return result;
@@ -220,7 +222,7 @@ ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::create(Proj
if (copy.buildDirectory.isEmpty()) { if (copy.buildDirectory.isEmpty()) {
copy.buildDirectory = shadowBuildDirectory(project->projectFilePath(), parent->kit(), copy.buildDirectory = shadowBuildDirectory(project->projectFilePath(), parent->kit(),
copy.displayName); copy.displayName, info->buildType);
} }
CMakeBuildConfiguration *bc = new CMakeBuildConfiguration(parent); CMakeBuildConfiguration *bc = new CMakeBuildConfiguration(parent);
@@ -306,18 +308,22 @@ CMakeBuildInfo *CMakeBuildConfigurationFactory::createBuildInfo(const ProjectExp
case BuildTypeDebug: case BuildTypeDebug:
info->arguments = QLatin1String("-DCMAKE_BUILD_TYPE=Debug"); info->arguments = QLatin1String("-DCMAKE_BUILD_TYPE=Debug");
info->typeName = tr("Debug"); info->typeName = tr("Debug");
info->buildType = BuildConfiguration::Debug;
break; break;
case BuildTypeRelease: case BuildTypeRelease:
info->arguments = QLatin1String("-DCMAKE_BUILD_TYPE=Release"); info->arguments = QLatin1String("-DCMAKE_BUILD_TYPE=Release");
info->typeName = tr("Release"); info->typeName = tr("Release");
info->buildType = BuildConfiguration::Release;
break; break;
case BuildTypeMinSizeRel: case BuildTypeMinSizeRel:
info->arguments = QLatin1String("-DCMAKE_BUILD_TYPE=MinSizeRel"); info->arguments = QLatin1String("-DCMAKE_BUILD_TYPE=MinSizeRel");
info->typeName = tr("Minimum Size Release"); info->typeName = tr("Minimum Size Release");
info->buildType = BuildConfiguration::Release;
break; break;
case BuildTypeRelWithDebInfo: case BuildTypeRelWithDebInfo:
info->arguments = QLatin1String("-DCMAKE_BUILD_TYPE=RelWithDebInfo"); info->arguments = QLatin1String("-DCMAKE_BUILD_TYPE=RelWithDebInfo");
info->typeName = tr("Release with Debug Information"); info->typeName = tr("Release with Debug Information");
info->buildType = BuildConfiguration::Profile;
break; break;
default: default:
QTC_CHECK(false); QTC_CHECK(false);

View File

@@ -265,10 +265,28 @@ void CMakeCbpParser::parseBuildTargetOption()
m_buildTarget.targetType = TargetType(value.toInt()); m_buildTarget.targetType = TargetType(value.toInt());
} else if (attributes().hasAttribute(QLatin1String("working_dir"))) { } else if (attributes().hasAttribute(QLatin1String("working_dir"))) {
m_buildTarget.workingDirectory = attributes().value(QLatin1String("working_dir")).toString(); m_buildTarget.workingDirectory = attributes().value(QLatin1String("working_dir")).toString();
QDir dir(m_buildDirectory);
const QString relative = dir.relativeFilePath(m_buildTarget.workingDirectory); QFile cmakeSourceInfoFile(m_buildTarget.workingDirectory
m_buildTarget.sourceDirectory + QStringLiteral("/CMakeFiles/CMakeDirectoryInformation.cmake"));
= FileName::fromString(m_sourceDirectory).appendPath(relative).toString(); if (cmakeSourceInfoFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream stream(&cmakeSourceInfoFile);
const QLatin1String searchSource("SET(CMAKE_RELATIVE_PATH_TOP_SOURCE \"");
while (!stream.atEnd()) {
const QString lineTopSource = stream.readLine().trimmed();
if (lineTopSource.startsWith(searchSource)) {
m_buildTarget.sourceDirectory = lineTopSource.mid(searchSource.size());
m_buildTarget.sourceDirectory.chop(2); // cut off ")
break;
}
}
}
if (m_buildTarget.sourceDirectory.isEmpty()) {
QDir dir(m_buildDirectory);
const QString relative = dir.relativeFilePath(m_buildTarget.workingDirectory);
m_buildTarget.sourceDirectory
= FileName::fromString(m_sourceDirectory).appendPath(relative).toString();
}
} }
while (!atEnd()) { while (!atEnd()) {
readNext(); readNext();

View File

@@ -61,6 +61,7 @@
#include <QStringList> #include <QStringList>
#include <QApplication> #include <QApplication>
#include <QCheckBox> #include <QCheckBox>
#include <QDir>
using namespace CMakeProjectManager; using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal; using namespace CMakeProjectManager::Internal;
@@ -495,7 +496,7 @@ void CMakeRunPage::initializePage()
"You can add command line arguments below. Note that " "You can add command line arguments below. Note that "
"CMake remembers command line arguments from the " "CMake remembers command line arguments from the "
"previous runs.") "previous runs.")
.arg(m_buildDirectory) .arg(QDir::toNativeSeparators(m_buildDirectory))
.arg(m_buildConfigurationName) .arg(m_buildConfigurationName)
.arg(m_kitName)); .arg(m_kitName));
} else if (m_mode == CMakeRunPage::Recreate) { } else if (m_mode == CMakeRunPage::Recreate) {
@@ -505,7 +506,7 @@ void CMakeRunPage::initializePage()
"Some projects require command line arguments to " "Some projects require command line arguments to "
"the initial CMake call. Note that CMake remembers command " "the initial CMake call. Note that CMake remembers command "
"line arguments from the previous runs.") "line arguments from the previous runs.")
.arg(m_buildDirectory) .arg(QDir::toNativeSeparators(m_buildDirectory))
.arg(m_buildConfigurationName) .arg(m_buildConfigurationName)
.arg(m_kitName)); .arg(m_kitName));
} else if (m_mode == CMakeRunPage::ChangeDirectory) { } else if (m_mode == CMakeRunPage::ChangeDirectory) {
@@ -516,7 +517,7 @@ void CMakeRunPage::initializePage()
} else if (m_mode == CMakeRunPage::WantToUpdate) { } else if (m_mode == CMakeRunPage::WantToUpdate) {
m_descriptionLabel->setText(tr("Refreshing the .cbp file in \"%1\" for build configuration \"%2\" " m_descriptionLabel->setText(tr("Refreshing the .cbp file in \"%1\" for build configuration \"%2\" "
"for target \"%3\".") "for target \"%3\".")
.arg(m_buildDirectory) .arg(QDir::toNativeSeparators(m_buildDirectory))
.arg(m_buildConfigurationName) .arg(m_buildConfigurationName)
.arg(m_kitName)); .arg(m_kitName));
} }

View File

@@ -60,13 +60,18 @@ EditorWindow::EditorWindow(QWidget *parent) :
connect(m_area, &EditorArea::windowTitleNeedsUpdate, connect(m_area, &EditorArea::windowTitleNeedsUpdate,
this, &EditorWindow::updateWindowTitle); this, &EditorWindow::updateWindowTitle);
// editor area can be deleted by editor manager
connect(m_area, &EditorArea::destroyed, this, [this]() {
m_area = nullptr;
deleteLater();
});
updateWindowTitle(); updateWindowTitle();
} }
EditorWindow::~EditorWindow() EditorWindow::~EditorWindow()
{ {
disconnect(m_area, &EditorArea::windowTitleNeedsUpdate, if (m_area)
this, &EditorWindow::updateWindowTitle); disconnect(m_area, 0, this, 0);
} }
EditorArea *EditorWindow::editorArea() const EditorArea *EditorWindow::editorArea() const

View File

@@ -214,6 +214,7 @@ void GdbServerStarter::attach(int port)
DebuggerRunParameters rp; DebuggerRunParameters rp;
rp.masterEngineType = GdbEngineType; rp.masterEngineType = GdbEngineType;
rp.connParams.host = d->device->sshParameters().host;
rp.connParams.port = port; rp.connParams.port = port;
rp.remoteChannel = rp.connParams.host + QLatin1Char(':') + QString::number(rp.connParams.port); rp.remoteChannel = rp.connParams.host + QLatin1Char(':') + QString::number(rp.connParams.port);
rp.displayName = tr("Remote: \"%1:%2\"").arg(rp.connParams.host).arg(port); rp.displayName = tr("Remote: \"%1:%2\"").arg(rp.connParams.host).arg(port);

View File

@@ -562,7 +562,7 @@ void parseChildrenData(const WatchData &data0, const GdbMi &item,
if (mi.isValid()) if (mi.isValid())
data.origaddr = mi.toAddress(); data.origaddr = mi.toAddress();
mi = item["addr"]; mi = item["address"];
if (mi.isValid()) if (mi.isValid())
setWatchDataAddress(data, mi.toAddress()); setWatchDataAddress(data, mi.toAddress());

View File

@@ -440,16 +440,16 @@ GerritChangePtr GerritModel::change(const QModelIndex &index) const
return GerritChangePtr(new GerritChange); return GerritChangePtr(new GerritChange);
} }
QString GerritModel::dependencyHtml(const QString &header, const QString &changeId, QString GerritModel::dependencyHtml(const QString &header, const int changeNumber,
const QString &serverPrefix) const const QString &serverPrefix) const
{ {
QString res; QString res;
if (changeId.isEmpty()) if (!changeNumber)
return res; return res;
QTextStream str(&res); QTextStream str(&res);
str << "<tr><td>" << header << "</td><td><a href=" str << "<tr><td>" << header << "</td><td><a href="
<< serverPrefix << "r/" << changeId << '>' << changeId << "</a>"; << serverPrefix << "r/" << changeNumber << '>' << changeNumber << "</a>";
if (const QStandardItem *item = itemForId(changeId)) if (const QStandardItem *item = itemForNumber(changeNumber))
str << " (" << changeFromItem(item)->title << ')'; str << " (" << changeFromItem(item)->title << ')';
str << "</td></tr>"; str << "</td></tr>";
return res; return res;
@@ -479,8 +479,8 @@ QString GerritModel::toHtml(const QModelIndex& index) const
<< "<tr><td>" << ownerHeader << "</td><td>" << c->owner << ' ' << "<tr><td>" << ownerHeader << "</td><td>" << c->owner << ' '
<< "<a href=\"mailto:" << c->email << "\">" << c->email << "</a></td></tr>" << "<a href=\"mailto:" << c->email << "\">" << c->email << "</a></td></tr>"
<< "<tr><td>" << projectHeader << "</td><td>" << c->project << " (" << c->branch << ")</td></tr>" << "<tr><td>" << projectHeader << "</td><td>" << c->project << " (" << c->branch << ")</td></tr>"
<< dependencyHtml(dependsOnHeader, c->dependsOnId, serverPrefix) << dependencyHtml(dependsOnHeader, c->dependsOnNumber, serverPrefix)
<< dependencyHtml(neededByHeader, c->neededById, serverPrefix) << dependencyHtml(neededByHeader, c->neededByNumber, serverPrefix)
<< "<tr><td>" << statusHeader << "</td><td>" << c->status << "<tr><td>" << statusHeader << "</td><td>" << c->status
<< ", " << c->lastUpdated.toString(Qt::DefaultLocaleShortDate) << "</td></tr>" << ", " << c->lastUpdated.toString(Qt::DefaultLocaleShortDate) << "</td></tr>"
<< "<tr><td>" << patchSetHeader << "</td><td>" << "</td></tr>" << c->currentPatchSet.patchSetNumber << "</td></tr>" << "<tr><td>" << patchSetHeader << "</td><td>" << "</td></tr>" << c->currentPatchSet.patchSetNumber << "</td></tr>"
@@ -490,25 +490,25 @@ QString GerritModel::toHtml(const QModelIndex& index) const
return result; return result;
} }
static QStandardItem *idSearchRecursion(QStandardItem *item, const QString &id) static QStandardItem *numberSearchRecursion(QStandardItem *item, int number)
{ {
if (changeFromItem(item)->id == id) if (changeFromItem(item)->number == number)
return item; return item;
const int rowCount = item->rowCount(); const int rowCount = item->rowCount();
for (int r = 0; r < rowCount; ++r) { for (int r = 0; r < rowCount; ++r) {
if (QStandardItem *i = idSearchRecursion(item->child(r, 0), id)) if (QStandardItem *i = numberSearchRecursion(item->child(r, 0), number))
return i; return i;
} }
return 0; return 0;
} }
QStandardItem *GerritModel::itemForId(const QString &id) const QStandardItem *GerritModel::itemForNumber(int number) const
{ {
if (id.isEmpty()) if (!number)
return 0; return 0;
const int numRows = rowCount(); const int numRows = rowCount();
for (int r = 0; r < numRows; ++r) { for (int r = 0; r < numRows; ++r) {
if (QStandardItem *i = idSearchRecursion(item(r, 0), id)) if (QStandardItem *i = numberSearchRecursion(item(r, 0), number))
return i; return i;
} }
return 0; return 0;
@@ -586,7 +586,6 @@ static bool parseOutput(const QSharedPointer<GerritParameters> &parameters,
{ {
// The output consists of separate lines containing a document each // The output consists of separate lines containing a document each
const QString typeKey = QLatin1String("type"); const QString typeKey = QLatin1String("type");
const QString idKey = QLatin1String("id");
const QString dependsOnKey = QLatin1String("dependsOn"); const QString dependsOnKey = QLatin1String("dependsOn");
const QString neededByKey = QLatin1String("neededBy"); const QString neededByKey = QLatin1String("neededBy");
const QString branchKey = QLatin1String("branch"); const QString branchKey = QLatin1String("branch");
@@ -656,7 +655,6 @@ static bool parseOutput(const QSharedPointer<GerritParameters> &parameters,
change->url = object.value(urlKey).toString(); change->url = object.value(urlKey).toString();
if (change->url.isEmpty()) // No "canonicalWebUrl" is in gerrit.config. if (change->url.isEmpty()) // No "canonicalWebUrl" is in gerrit.config.
change->url = defaultUrl(parameters, change->number); change->url = defaultUrl(parameters, change->number);
change->id = object.value(idKey).toString();
change->title = object.value(titleKey).toString(); change->title = object.value(titleKey).toString();
const QJsonObject ownerJ = object.value(ownerKey).toObject(); const QJsonObject ownerJ = object.value(ownerKey).toObject();
change->owner = ownerJ.value(ownerNameKey).toString(); change->owner = ownerJ.value(ownerNameKey).toString();
@@ -681,7 +679,7 @@ static bool parseOutput(const QSharedPointer<GerritParameters> &parameters,
if (!dependsOnArray.isEmpty()) { if (!dependsOnArray.isEmpty()) {
const QJsonValue first = dependsOnArray.at(0); const QJsonValue first = dependsOnArray.at(0);
if (first.isObject()) if (first.isObject())
change->dependsOnId = first.toObject()[idKey].toString(); change->dependsOnNumber = first.toObject()[numberKey].toString().toInt();
} }
} }
// Read out needed by // Read out needed by
@@ -691,7 +689,7 @@ static bool parseOutput(const QSharedPointer<GerritParameters> &parameters,
if (!neededByArray.isEmpty()) { if (!neededByArray.isEmpty()) {
const QJsonValue first = neededByArray.at(0); const QJsonValue first = neededByArray.at(0);
if (first.isObject()) if (first.isObject())
change->neededById = first.toObject()[idKey].toString(); change->neededByNumber = first.toObject()[numberKey].toString().toInt();
} }
} }
} }
@@ -757,17 +755,17 @@ void GerritModel::queryFinished(const QByteArray &output)
setState(parseOutput(m_parameters, output, changes) ? Ok : Error); setState(parseOutput(m_parameters, output, changes) ? Ok : Error);
// Populate a hash with indices for faster access. // Populate a hash with indices for faster access.
QHash<QString, int> idIndexHash; QHash<int, int> numberIndexHash;
const int count = changes.size(); const int count = changes.size();
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
idIndexHash.insert(changes.at(i)->id, i); numberIndexHash.insert(changes.at(i)->number, i);
// Mark root nodes: Changes that do not have a dependency, depend on a change // Mark root nodes: Changes that do not have a dependency, depend on a change
// not in the list or on a change that is not "NEW". // not in the list or on a change that is not "NEW".
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
if (changes.at(i)->dependsOnId.isEmpty()) { if (!changes.at(i)->dependsOnNumber) {
changes.at(i)->depth = 0; changes.at(i)->depth = 0;
} else { } else {
const int dependsOnIndex = idIndexHash.value(changes.at(i)->dependsOnId, -1); const int dependsOnIndex = numberIndexHash.value(changes.at(i)->dependsOnNumber, -1);
if (dependsOnIndex < 0 || changes.at(dependsOnIndex)->status != QLatin1String("NEW")) if (dependsOnIndex < 0 || changes.at(dependsOnIndex)->status != QLatin1String("NEW"))
changes.at(i)->depth = 0; changes.at(i)->depth = 0;
} }
@@ -778,7 +776,7 @@ void GerritModel::queryFinished(const QByteArray &output)
changed = false; changed = false;
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
if (changes.at(i)->depth < 0) { if (changes.at(i)->depth < 0) {
const int dependsIndex = idIndexHash.value(changes.at(i)->dependsOnId); const int dependsIndex = numberIndexHash.value(changes.at(i)->dependsOnNumber);
const int dependsOnDepth = changes.at(dependsIndex)->depth; const int dependsOnDepth = changes.at(dependsIndex)->depth;
if (dependsOnDepth >= 0) { if (dependsOnDepth >= 0) {
changes.at(i)->depth = dependsOnDepth + 1; changes.at(i)->depth = dependsOnDepth + 1;
@@ -789,19 +787,19 @@ void GerritModel::queryFinished(const QByteArray &output)
} }
// Sort by depth (root nodes first) and by date. // Sort by depth (root nodes first) and by date.
qStableSort(changes.begin(), changes.end(), gerritChangeLessThan); qStableSort(changes.begin(), changes.end(), gerritChangeLessThan);
idIndexHash.clear(); numberIndexHash.clear();
foreach (const GerritChangePtr &c, changes) { foreach (const GerritChangePtr &c, changes) {
// Avoid duplicate entries for example in the (unlikely) // Avoid duplicate entries for example in the (unlikely)
// case people do self-reviews. // case people do self-reviews.
if (!itemForId(c->id)) { if (!itemForNumber(c->number)) {
// Determine the verbose user name from the owner of the first query. // Determine the verbose user name from the owner of the first query.
// It used for marking the changes pending for review in bold. // It used for marking the changes pending for review in bold.
if (m_userName.isEmpty() && !m_query->currentQuery()) if (m_userName.isEmpty() && !m_query->currentQuery())
m_userName = c->owner; m_userName = c->owner;
const QList<QStandardItem *> newRow = changeToRow(c); const QList<QStandardItem *> newRow = changeToRow(c);
if (c->depth) { if (c->depth) {
QStandardItem *parent = itemForId(c->dependsOnId); QStandardItem *parent = itemForNumber(c->dependsOnNumber);
// Append changes with depth > 1 to the parent with depth=1 to avoid // Append changes with depth > 1 to the parent with depth=1 to avoid
// too-deeply nested items. // too-deeply nested items.
for (; changeFromItem(parent)->depth >= 1; parent = parent->parent()) {} for (; changeFromItem(parent)->depth >= 1; parent = parent->parent()) {}

View File

@@ -79,9 +79,8 @@ public:
QString url; QString url;
int number; int number;
QString id; int dependsOnNumber;
QString dependsOnId; int neededByNumber;
QString neededById;
QString title; QString title;
QString owner; QString owner;
QString email; QString email;
@@ -123,7 +122,7 @@ public:
GerritChangePtr change(const QModelIndex &index) const; GerritChangePtr change(const QModelIndex &index) const;
QString toHtml(const QModelIndex &index) const; QString toHtml(const QModelIndex &index) const;
QStandardItem *itemForId(const QString &id) const; QStandardItem *itemForNumber(int number) const;
enum QueryState { Idle, Running, Ok, Error }; enum QueryState { Idle, Running, Ok, Error };
QueryState state() const { return m_state; } QueryState state() const { return m_state; }
@@ -141,7 +140,7 @@ private:
void setState(QueryState s); void setState(QueryState s);
QString dependencyHtml(const QString &header, const QString &changeId, QString dependencyHtml(const QString &header, const int changeNumber,
const QString &serverPrefix) const; const QString &serverPrefix) const;
QList<QStandardItem *> changeToRow(const GerritChangePtr &c) const; QList<QStandardItem *> changeToRow(const GerritChangePtr &c) const;

View File

@@ -2984,6 +2984,7 @@ VcsCommand *GitClient::vcsExecAbortable(const QString &workingDirectory,
// Git might request an editor, so this must be done asynchronously and without timeout // Git might request an editor, so this must be done asynchronously and without timeout
VcsCommand *command = createCommand(workingDirectory, 0, VcsWindowOutputBind); VcsCommand *command = createCommand(workingDirectory, 0, VcsWindowOutputBind);
command->setCookie(workingDirectory); command->setCookie(workingDirectory);
command->addFlags(VcsCommand::ShowSuccessMessage);
command->addJob(vcsBinary(), arguments, 0); command->addJob(vcsBinary(), arguments, 0);
command->execute(); command->execute();
ConflictHandler::attachToCommand(command, abortCommand); ConflictHandler::attachToCommand(command, abortCommand);

View File

@@ -375,10 +375,10 @@ QList<ToolChain *> IosToolChainFactory::autoDetect(const QList<ToolChain *> &exi
foreach (const Platform &platform, platforms) { foreach (const Platform &platform, platforms) {
ClangToolChain *toolChain = findToolChainForPlatform(platform, existingClangToolChains); ClangToolChain *toolChain = findToolChainForPlatform(platform, existingClangToolChains);
if (!toolChain) { if (!toolChain) {
ClangToolChain *newToolChain = createToolChain(platform); toolChain = createToolChain(platform);
toolChains.append(newToolChain); existingClangToolChains.append(toolChain);
existingClangToolChains.append(newToolChain);
} }
toolChains.append(toolChain);
} }
return Utils::transform(toolChains, [](ClangToolChain *tc) -> ToolChain * { return tc; }); return Utils::transform(toolChains, [](ClangToolChain *tc) -> ToolChain * { return tc; });
} }

View File

@@ -74,9 +74,8 @@ Core::IDocument::OpenResult ModelDocument::open(QString *errorString, const QStr
{ {
Q_UNUSED(fileName); Q_UNUSED(fileName);
if (!load(errorString, realFileName)) OpenResult result = load(errorString, realFileName);
return Core::IDocument::OpenResult::ReadError; return result;
return Core::IDocument::OpenResult::Success;
} }
bool ModelDocument::save(QString *errorString, const QString &name, bool autoSave) bool ModelDocument::save(QString *errorString, const QString &name, bool autoSave)
@@ -143,7 +142,7 @@ ExtDocumentController *ModelDocument::documentController() const
return d->documentController; return d->documentController;
} }
bool ModelDocument::load(QString *errorString, const QString &fileName) Core::IDocument::OpenResult ModelDocument::load(QString *errorString, const QString &fileName)
{ {
d->documentController = ModelEditorPlugin::modelsManager()->createModel(this); d->documentController = ModelEditorPlugin::modelsManager()->createModel(this);
connect(d->documentController, &qmt::DocumentController::changed, this, &IDocument::changed); connect(d->documentController, &qmt::DocumentController::changed, this, &IDocument::changed);
@@ -151,13 +150,16 @@ bool ModelDocument::load(QString *errorString, const QString &fileName)
try { try {
d->documentController->loadProject(fileName); d->documentController->loadProject(fileName);
setFilePath(Utils::FileName::fromString(d->documentController->getProjectController()->getProject()->getFileName())); setFilePath(Utils::FileName::fromString(d->documentController->getProjectController()->getProject()->getFileName()));
} catch (const qmt::Exception &ex) { } catch (const qmt::FileNotFoundException &ex) {
*errorString = ex.getErrorMsg(); *errorString = ex.getErrorMsg();
return false; return OpenResult::ReadError;
} catch (const qmt::Exception &ex) {
*errorString = tr("Could not open \"%1\" for reading: %2.").arg(fileName).arg(ex.getErrorMsg());
return OpenResult::CannotHandle;
} }
emit contentSet(); emit contentSet();
return true; return OpenResult::Success;
} }
} // namespace Internal } // namespace Internal

View File

@@ -54,7 +54,7 @@ signals:
void contentSet(); void contentSet();
public: public:
IDocument::OpenResult open(QString *errorString, const QString &fileName, OpenResult open(QString *errorString, const QString &fileName,
const QString &realFileName) override; const QString &realFileName) override;
bool save(QString *errorString, const QString &fileName, bool autoSave) override; bool save(QString *errorString, const QString &fileName, bool autoSave) override;
QString defaultPath() const override; QString defaultPath() const override;
@@ -65,7 +65,7 @@ public:
ExtDocumentController *documentController() const; ExtDocumentController *documentController() const;
bool load(QString *errorString, const QString &fileName); OpenResult load(QString *errorString, const QString &fileName);
private: private:
ModelDocumentPrivate *d; ModelDocumentPrivate *d;

View File

@@ -33,6 +33,7 @@
#include "projectexplorer_export.h" #include "projectexplorer_export.h"
#include "buildconfiguration.h"
#include "task.h" #include "task.h"
#include <coreplugin/id.h> #include <coreplugin/id.h>
@@ -54,6 +55,14 @@ public:
QString typeName; QString typeName;
Utils::FileName buildDirectory; Utils::FileName buildDirectory;
Core::Id kitId; Core::Id kitId;
BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown;
bool operator==(const BuildInfo &o)
{
return displayName == o.displayName && typeName == o.typeName
&& buildDirectory == o.buildDirectory && kitId == o.kitId
&& buildType == o.buildType;
}
virtual QList<Task> reportIssues(const QString &projectPath, virtual QList<Task> reportIssues(const QString &projectPath,
const QString &buildDir) const const QString &buildDir) const

View File

@@ -779,10 +779,13 @@ QList<ToolChain *> GccToolChainFactory::autoDetect(const QList<ToolChain *> &alr
QList<ToolChain *> tcs; QList<ToolChain *> tcs;
if (HostOsInfo::isMacHost()) { if (HostOsInfo::isMacHost()) {
// Old mac compilers needed to support macx-gccXY mkspecs: // Old mac compilers needed to support macx-gccXY mkspecs:
tcs.append(autoDetectToolchains(QLatin1String("g++-4.0"), Abi::hostAbi(), alreadyKnown)); tcs.append(autoDetectToolchains(QLatin1String("g++-4.0"), Abi::hostAbi(),
tcs.append(autoDetectToolchains(QLatin1String("g++-4.2"), Abi::hostAbi(), alreadyKnown)); Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown));
tcs.append(autoDetectToolchains(QLatin1String("g++-4.2"), Abi::hostAbi(),
Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown));
} }
tcs.append(autoDetectToolchains(QLatin1String("g++"), Abi::hostAbi(), alreadyKnown)); tcs.append(autoDetectToolchains(QLatin1String("g++"), Abi::hostAbi(),
Constants::GCC_TOOLCHAIN_TYPEID,alreadyKnown));
return tcs; return tcs;
} }
@@ -810,6 +813,7 @@ GccToolChain *GccToolChainFactory::createToolChain(bool autoDetect)
QList<ToolChain *> GccToolChainFactory::autoDetectToolchains(const QString &compiler, QList<ToolChain *> GccToolChainFactory::autoDetectToolchains(const QString &compiler,
const Abi &requiredAbi, const Abi &requiredAbi,
const Core::Id requiredTypeId,
const QList<ToolChain *> &alreadyKnown) const QList<ToolChain *> &alreadyKnown)
{ {
QList<ToolChain *> result; QList<ToolChain *> result;
@@ -819,7 +823,11 @@ QList<ToolChain *> GccToolChainFactory::autoDetectToolchains(const QString &comp
if (compilerPath.isEmpty()) if (compilerPath.isEmpty())
return result; return result;
if (Utils::findOrDefault(alreadyKnown, Utils::equal(&ToolChain::compilerCommand, compilerPath))) result = Utils::filtered(alreadyKnown, [requiredTypeId, compilerPath](ToolChain *tc) {
return tc->typeId() == requiredTypeId
&& tc->compilerCommand() == compilerPath;
});
if (!result.isEmpty())
return result; return result;
GccToolChain::addCommandPathToEnvironment(compilerPath, systemEnvironment); GccToolChain::addCommandPathToEnvironment(compilerPath, systemEnvironment);
@@ -1113,7 +1121,8 @@ ClangToolChainFactory::ClangToolChainFactory()
QList<ToolChain *> ClangToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) QList<ToolChain *> ClangToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{ {
return autoDetectToolchains(QLatin1String("clang++"), Abi::hostAbi(), alreadyKnown); return autoDetectToolchains(QLatin1String("clang++"), Abi::hostAbi(),
Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown);
} }
bool ClangToolChainFactory::canRestore(const QVariantMap &data) bool ClangToolChainFactory::canRestore(const QVariantMap &data)
@@ -1193,7 +1202,8 @@ QList<ToolChain *> MingwToolChainFactory::autoDetect(const QList<ToolChain *> &a
{ {
Abi ha = Abi::hostAbi(); Abi ha = Abi::hostAbi();
ha = Abi(ha.architecture(), Abi::WindowsOS, Abi::WindowsMSysFlavor, Abi::PEFormat, ha.wordWidth()); ha = Abi(ha.architecture(), Abi::WindowsOS, Abi::WindowsMSysFlavor, Abi::PEFormat, ha.wordWidth());
return autoDetectToolchains(QLatin1String("g++"), ha, alreadyKnown); return autoDetectToolchains(QLatin1String("g++"), ha,
Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown);
} }
bool MingwToolChainFactory::canRestore(const QVariantMap &data) bool MingwToolChainFactory::canRestore(const QVariantMap &data)
@@ -1268,7 +1278,8 @@ LinuxIccToolChainFactory::LinuxIccToolChainFactory()
QList<ToolChain *> LinuxIccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) QList<ToolChain *> LinuxIccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{ {
return autoDetectToolchains(QLatin1String("icpc"), Abi::hostAbi(), alreadyKnown); return autoDetectToolchains(QLatin1String("icpc"), Abi::hostAbi(),
Constants::LINUXICC_TOOLCHAIN_TYPEID, alreadyKnown);
} }
bool LinuxIccToolChainFactory::canRestore(const QVariantMap &data) bool LinuxIccToolChainFactory::canRestore(const QVariantMap &data)

View File

@@ -66,8 +66,8 @@ public:
protected: protected:
virtual GccToolChain *createToolChain(bool autoDetect); virtual GccToolChain *createToolChain(bool autoDetect);
QList<ToolChain *> autoDetectToolchains(const QString &compiler, QList<ToolChain *> autoDetectToolchains(const QString &compiler, const Abi &requiredAbi,
const Abi &, const Core::Id requiredTypeId,
const QList<ToolChain *> &alreadyKnown); const QList<ToolChain *> &alreadyKnown);
}; };

View File

@@ -33,6 +33,7 @@
#include "msvcparser.h" #include "msvcparser.h"
#include "projectexplorerconstants.h" #include "projectexplorerconstants.h"
#include <utils/algorithm.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <utils/winutils.h> #include <utils/winutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -526,9 +527,26 @@ QString MsvcToolChainFactory::vcVarsBatFor(const QString &basePath, MsvcToolChai
return vcVarsBatFor(basePath, platformName(platform)); return vcVarsBatFor(basePath, platformName(platform));
} }
static ToolChain *findOrCreateToolChain(const QList<ToolChain *> &alreadyKnown,
const QString &name, const Abi &abi,
const QString &varsBat, const QString &varsBatArg,
ToolChain::Detection d = ToolChain::ManualDetection)
{
ToolChain *tc = Utils::findOrDefault(alreadyKnown,
[&varsBat, &varsBatArg](ToolChain *tc) -> bool {
if (tc->typeId() != Constants::MSVC_TOOLCHAIN_TYPEID)
return false;
auto mtc = static_cast<MsvcToolChain *>(tc);
return mtc->varsBat() == varsBat
&& mtc->varsBatArg() == varsBatArg;
});
if (!tc)
tc = new MsvcToolChain(name, abi, varsBat, varsBatArg, d);
return tc;
}
QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{ {
Q_UNUSED(alreadyKnown);
QList<ToolChain *> results; QList<ToolChain *> results;
// 1) Installed SDKs preferred over standalone Visual studio // 1) Installed SDKs preferred over standalone Visual studio
@@ -550,16 +568,19 @@ QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &al
continue; continue;
QList<ToolChain *> tmp; QList<ToolChain *> tmp;
tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::x86), tmp.append(findOrCreateToolChain(alreadyKnown,
findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::x86, sdkKey), generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::x86),
fi.absoluteFilePath(), QLatin1String("/x86"), ToolChain::AutoDetection)); findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::x86, sdkKey),
fi.absoluteFilePath(), QLatin1String("/x86"), ToolChain::AutoDetection));
// Add all platforms, cross-compiler is automatically selected by SetEnv.cmd if needed // Add all platforms, cross-compiler is automatically selected by SetEnv.cmd if needed
tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::amd64), tmp.append(findOrCreateToolChain(alreadyKnown,
findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::amd64, sdkKey), generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::amd64),
fi.absoluteFilePath(), QLatin1String("/x64"), ToolChain::AutoDetection)); findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::amd64, sdkKey),
tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::ia64), fi.absoluteFilePath(), QLatin1String("/x64"), ToolChain::AutoDetection));
findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::ia64, sdkKey), tmp.append(findOrCreateToolChain(alreadyKnown,
fi.absoluteFilePath(), QLatin1String("/ia64"), ToolChain::AutoDetection)); generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::ia64),
findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::ia64, sdkKey),
fi.absoluteFilePath(), QLatin1String("/ia64"), ToolChain::AutoDetection));
// Make sure the default is front. // Make sure the default is front.
if (folder == defaultSdkPath) if (folder == defaultSdkPath)
results = tmp + results; results = tmp + results;
@@ -601,11 +622,11 @@ QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &al
foreach (const MsvcToolChain::Platform &platform, platforms) { foreach (const MsvcToolChain::Platform &platform, platforms) {
if (hostSupportsPlatform(platform) if (hostSupportsPlatform(platform)
&& QFileInfo(vcVarsBatFor(path, platform)).isFile()) { && QFileInfo(vcVarsBatFor(path, platform)).isFile()) {
results.append(new MsvcToolChain( results.append(findOrCreateToolChain(
alreadyKnown,
generateDisplayName(vsName, MsvcToolChain::VS, platform), generateDisplayName(vsName, MsvcToolChain::VS, platform),
findAbiOfMsvc(MsvcToolChain::VS, platform, vsName), findAbiOfMsvc(MsvcToolChain::VS, platform, vsName),
vcvarsAllbat, vcvarsAllbat, platformName(platform),
platformName(platform),
ToolChain::AutoDetection)); ToolChain::AutoDetection));
} }
} }

View File

@@ -85,7 +85,7 @@
#include "taskhub.h" #include "taskhub.h"
#include "customtoolchain.h" #include "customtoolchain.h"
#include "selectablefilesmodel.h" #include "selectablefilesmodel.h"
#include <projectexplorer/customwizard/customwizard.h> #include "customwizard/customwizard.h"
#include "devicesupport/desktopdevice.h" #include "devicesupport/desktopdevice.h"
#include "devicesupport/desktopdevicefactory.h" #include "devicesupport/desktopdevicefactory.h"
#include "devicesupport/devicemanager.h" #include "devicesupport/devicemanager.h"
@@ -106,7 +106,6 @@
#include <extensionsystem/pluginspec.h> #include <extensionsystem/pluginspec.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/id.h> #include <coreplugin/id.h>
#include <coreplugin/idocumentfactory.h> #include <coreplugin/idocumentfactory.h>
#include <coreplugin/idocument.h> #include <coreplugin/idocument.h>
@@ -117,7 +116,6 @@
#include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h> #include <coreplugin/actionmanager/command.h>
#include <coreplugin/infobar.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/findplaceholder.h> #include <coreplugin/findplaceholder.h>
#include <coreplugin/vcsmanager.h> #include <coreplugin/vcsmanager.h>
@@ -143,11 +141,11 @@
#include <QAction> #include <QAction>
#include <QApplication> #include <QApplication>
#include <QDir>
#include <QFileDialog> #include <QFileDialog>
#include <QMenu> #include <QMenu>
#include <QMessageBox> #include <QMessageBox>
#include <QTimer> #include <QTimer>
#include <QWizard>
/*! /*!
\namespace ProjectExplorer \namespace ProjectExplorer
@@ -3141,7 +3139,8 @@ void ProjectExplorerPluginPrivate::handleAddExistingFiles()
tr("Add Existing Files"), directoryFor(ProjectTree::currentNode())); tr("Add Existing Files"), directoryFor(ProjectTree::currentNode()));
if (fileNames.isEmpty()) if (fileNames.isEmpty())
return; return;
ProjectExplorerPlugin::addExistingFiles(fileNames, folderNode);
ProjectExplorerPlugin::addExistingFiles(folderNode, fileNames);
} }
void ProjectExplorerPluginPrivate::addExistingDirectory() void ProjectExplorerPluginPrivate::addExistingDirectory()
@@ -3154,12 +3153,7 @@ void ProjectExplorerPluginPrivate::addExistingDirectory()
SelectableFilesDialogAddDirectory dialog(directoryFor(ProjectTree::currentNode()), QStringList(), ICore::mainWindow()); SelectableFilesDialogAddDirectory dialog(directoryFor(ProjectTree::currentNode()), QStringList(), ICore::mainWindow());
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
ProjectExplorerPlugin::addExistingFiles(dialog.selectedFiles(), folderNode); ProjectExplorerPlugin::addExistingFiles(folderNode, dialog.selectedFiles());
}
void ProjectExplorerPlugin::addExistingFiles(const QStringList &filePaths, FolderNode *folderNode)
{
addExistingFiles(folderNode, filePaths);
} }
void ProjectExplorerPlugin::addExistingFiles(FolderNode *folderNode, const QStringList &filePaths) void ProjectExplorerPlugin::addExistingFiles(FolderNode *folderNode, const QStringList &filePaths)
@@ -3173,13 +3167,15 @@ void ProjectExplorerPlugin::addExistingFiles(FolderNode *folderNode, const QStri
folderNode->addFiles(fileNames, &notAdded); folderNode->addFiles(fileNames, &notAdded);
if (!notAdded.isEmpty()) { if (!notAdded.isEmpty()) {
QString message = tr("Could not add following files to project %1:").arg(folderNode->projectNode()->displayName()); const QString message = tr("Could not add following files to project %1:")
message += QLatin1Char('\n'); .arg(folderNode->projectNode()->displayName()) + QLatin1Char('\n');
QString files = notAdded.join(QLatin1Char('\n')); const QStringList nativeFiles
= Utils::transform(notAdded,
[](const QString &f) { return QDir::toNativeSeparators(f); });
QMessageBox::warning(ICore::mainWindow(), tr("Adding Files to Project Failed"), QMessageBox::warning(ICore::mainWindow(), tr("Adding Files to Project Failed"),
message + files); message + nativeFiles.join(QLatin1Char('\n')));
foreach (const QString &file, notAdded) fileNames = Utils::filtered(fileNames,
fileNames.removeOne(file); [&notAdded](const QString &f) { return !notAdded.contains(f); });
} }
VcsManager::promptToAdd(dir, fileNames); VcsManager::promptToAdd(dir, fileNames);
@@ -3245,7 +3241,9 @@ void ProjectExplorerPluginPrivate::removeFile()
if (!folderNode->removeFiles(QStringList(filePath))) { if (!folderNode->removeFiles(QStringList(filePath))) {
QMessageBox::warning(ICore::mainWindow(), tr("Removing File Failed"), QMessageBox::warning(ICore::mainWindow(), tr("Removing File Failed"),
tr("Could not remove file %1 from project %2.").arg(filePath).arg(folderNode->projectNode()->displayName())); tr("Could not remove file %1 from project %2.")
.arg(QDir::toNativeSeparators(filePath))
.arg(folderNode->projectNode()->displayName()));
return; return;
} }
@@ -3266,7 +3264,8 @@ void ProjectExplorerPluginPrivate::deleteFile()
QMessageBox::StandardButton button = QMessageBox::StandardButton button =
QMessageBox::question(ICore::mainWindow(), QMessageBox::question(ICore::mainWindow(),
tr("Delete File"), tr("Delete File"),
tr("Delete %1 from file system?").arg(filePath), tr("Delete %1 from file system?")
.arg(QDir::toNativeSeparators(filePath)),
QMessageBox::Yes | QMessageBox::No); QMessageBox::Yes | QMessageBox::No);
if (button != QMessageBox::Yes) if (button != QMessageBox::Yes)
return; return;
@@ -3285,7 +3284,8 @@ void ProjectExplorerPluginPrivate::deleteFile()
if (file.exists()) { if (file.exists()) {
if (!file.remove()) if (!file.remove())
QMessageBox::warning(ICore::mainWindow(), tr("Deleting File Failed"), QMessageBox::warning(ICore::mainWindow(), tr("Deleting File Failed"),
tr("Could not delete file %1.").arg(filePath)); tr("Could not delete file %1.")
.arg(QDir::toNativeSeparators(filePath)));
} }
DocumentManager::unexpectFileChange(filePath); DocumentManager::unexpectFileChange(filePath);
} }
@@ -3309,7 +3309,6 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &newFilePath)
FolderNode *folderNode = node->parentFolderNode(); FolderNode *folderNode = node->parentFolderNode();
QString projectFileName = folderNode->projectNode()->path().fileName(); QString projectFileName = folderNode->projectNode()->path().fileName();
if (!folderNode->canRenameFile(orgFilePath, newFilePath)) { if (!folderNode->canRenameFile(orgFilePath, newFilePath)) {
QTimer::singleShot(0, [orgFilePath, newFilePath, projectFileName] { QTimer::singleShot(0, [orgFilePath, newFilePath, projectFileName] {
int res = QMessageBox::question(ICore::mainWindow(), int res = QMessageBox::question(ICore::mainWindow(),
@@ -3317,8 +3316,8 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &newFilePath)
tr("The project file %1 cannot be automatically changed.\n\n" tr("The project file %1 cannot be automatically changed.\n\n"
"Rename %2 to %3 anyway?") "Rename %2 to %3 anyway?")
.arg(projectFileName) .arg(projectFileName)
.arg(orgFilePath) .arg(QDir::toNativeSeparators(orgFilePath))
.arg(newFilePath)); .arg(QDir::toNativeSeparators(newFilePath)));
if (res == QMessageBox::Yes) if (res == QMessageBox::Yes)
FileUtils::renameFile(orgFilePath, newFilePath); FileUtils::renameFile(orgFilePath, newFilePath);
@@ -3329,9 +3328,10 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &newFilePath)
if (FileUtils::renameFile(orgFilePath, newFilePath)) { if (FileUtils::renameFile(orgFilePath, newFilePath)) {
// Tell the project plugin about rename // Tell the project plugin about rename
if (!folderNode->renameFile(orgFilePath, newFilePath)) { if (!folderNode->renameFile(orgFilePath, newFilePath)) {
QString renameFileError = tr("The file %1 was renamed to %2, but the project file %3 could not be automatically changed.") const QString renameFileError
.arg(orgFilePath) = tr("The file %1 was renamed to %2, but the project file %3 could not be automatically changed.")
.arg(newFilePath) .arg(QDir::toNativeSeparators(orgFilePath))
.arg(QDir::toNativeSeparators(newFilePath))
.arg(projectFileName); .arg(projectFileName);
QTimer::singleShot(0, [renameFileError]() { QTimer::singleShot(0, [renameFileError]() {
@@ -3340,6 +3340,16 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &newFilePath)
renameFileError); renameFileError);
}); });
} }
} else {
const QString renameFileError = tr("The file %1 could not be renamed %2.")
.arg(QDir::toNativeSeparators(orgFilePath))
.arg(QDir::toNativeSeparators(newFilePath));
QTimer::singleShot(0, [renameFileError]() {
QMessageBox::warning(ICore::mainWindow(),
tr("Cannot Rename File"),
renameFileError);
});
} }
} }

View File

@@ -144,8 +144,7 @@ public:
static void runRunConfiguration(RunConfiguration *rc, Core::Id runMode, static void runRunConfiguration(RunConfiguration *rc, Core::Id runMode,
const bool forceSkipDeploy = false); const bool forceSkipDeploy = false);
static void addExistingFiles(FolderNode *projectNode, const QStringList &filePaths); static void addExistingFiles(FolderNode *folderNode, const QStringList &filePaths);
static void addExistingFiles(const QStringList &filePaths, FolderNode *folderNode);
static void buildProject(Project *p); static void buildProject(Project *p);
/// Normally there's no need to call this function. /// Normally there's no need to call this function.
@@ -219,6 +218,9 @@ private slots:
void testAbiFromTargetTriplet(); void testAbiFromTargetTriplet();
void testDeviceManager(); void testDeviceManager();
void testToolChainManager_data();
void testToolChainManager();
#endif #endif
}; };

View File

@@ -35,7 +35,8 @@
namespace ProjectExplorer { namespace ProjectExplorer {
ProjectMacroExpander::ProjectMacroExpander(const QString &projectName, ProjectMacroExpander::ProjectMacroExpander(const QString &projectName,
const Kit *kit, const QString &bcName) const Kit *kit, const QString &bcName,
BuildConfiguration::BuildType buildType)
{ {
registerVariable(Constants::VAR_CURRENTPROJECT_NAME, registerVariable(Constants::VAR_CURRENTPROJECT_NAME,
QCoreApplication::translate("ProjectExplorer", "Name of current project"), QCoreApplication::translate("ProjectExplorer", "Name of current project"),
@@ -45,6 +46,10 @@ ProjectMacroExpander::ProjectMacroExpander(const QString &projectName,
QCoreApplication::translate("ProjectExplorer", "Name of current build"), QCoreApplication::translate("ProjectExplorer", "Name of current build"),
[bcName] { return bcName; }); [bcName] { return bcName; });
registerVariable(Constants::VAR_CURRENTBUILD_TYPE,
QCoreApplication::translate("ProjectExplorer", "Type of current build"),
[buildType] { return BuildConfiguration::buildTypeName(buildType); });
registerSubProvider([kit] { return kit->macroExpander(); }); registerSubProvider([kit] { return kit->macroExpander(); });
} }

View File

@@ -32,6 +32,9 @@
#define PROJECTMACROEXPANDER_H #define PROJECTMACROEXPANDER_H
#include "projectexplorer_export.h" #include "projectexplorer_export.h"
#include "buildconfiguration.h"
#include <utils/macroexpander.h> #include <utils/macroexpander.h>
namespace ProjectExplorer { namespace ProjectExplorer {
@@ -40,7 +43,8 @@ class Kit;
class PROJECTEXPLORER_EXPORT ProjectMacroExpander : public Utils::MacroExpander class PROJECTEXPLORER_EXPORT ProjectMacroExpander : public Utils::MacroExpander
{ {
public: public:
ProjectMacroExpander(const QString &projectName, const Kit *kit, const QString &bcName); ProjectMacroExpander(const QString &projectName, const Kit *kit, const QString &bcName,
BuildConfiguration::BuildType buildType);
}; };
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -278,6 +278,7 @@ int ProjectTreeWidget::expandedCount(Node *node)
void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int end) void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int end)
{ {
Node *node = m_model->nodeForIndex(parent); Node *node = m_model->nodeForIndex(parent);
QTC_ASSERT(node, return);
const QString path = node->path().toString(); const QString path = node->path().toString();
const QString displayName = node->displayName(); const QString displayName = node->displayName();

View File

@@ -50,7 +50,6 @@ static const char TOOLCHAIN_DATA_KEY[] = "ToolChain.";
static const char TOOLCHAIN_COUNT_KEY[] = "ToolChain.Count"; static const char TOOLCHAIN_COUNT_KEY[] = "ToolChain.Count";
static const char TOOLCHAIN_FILE_VERSION_KEY[] = "Version"; static const char TOOLCHAIN_FILE_VERSION_KEY[] = "Version";
static const char TOOLCHAIN_FILENAME[] = "/qtcreator/toolchains.xml"; static const char TOOLCHAIN_FILENAME[] = "/qtcreator/toolchains.xml";
static const char LEGACY_TOOLCHAIN_FILENAME[] = "/toolChains.xml";
using namespace Utils; using namespace Utils;
@@ -167,98 +166,146 @@ static QList<ToolChain *> restoreFromFile(const FileName &fileName)
return result; return result;
} }
static QList<ToolChain *> autoDetectToolChains(const QList<ToolChain *> alreadyKnownTcs)
{
QList<ToolChain *> result;
const QList<ToolChainFactory *> factories
= ExtensionSystem::PluginManager::getObjects<ToolChainFactory>();
foreach (ToolChainFactory *f, factories)
result.append(f->autoDetect(alreadyKnownTcs));
return result;
}
static QList<ToolChain *> subtractByEqual(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
{
return Utils::filtered(a, [&b](ToolChain *atc) {
return !Utils::anyOf(b, [atc](ToolChain *btc) { return *atc == *btc; });
});
}
static QList<ToolChain *> subtractByPointerEqual(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
{
return Utils::filtered(a, [&b](ToolChain *atc) { return !b.contains(atc); });
}
static QList<ToolChain *> subtractById(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
{
return Utils::filtered(a, [&b](ToolChain *atc) {
return !Utils::anyOf(b, Utils::equal(&ToolChain::id, atc->id()));
});
}
static QList<ToolChain *> intersectByEqual(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
{
return Utils::filtered(a, [&b](ToolChain *atc) {
return Utils::anyOf(b, [atc](ToolChain *btc) { return *atc == *btc; });
});
}
static QList<ToolChain *> makeUnique(const QList<ToolChain *> &a)
{
return QSet<ToolChain *>::fromList(a).toList();
}
namespace {
struct ToolChainOperations
{
QList<ToolChain *> toDemote;
QList<ToolChain *> toRegister;
QList<ToolChain *> toDelete;
};
} // namespace
static ToolChainOperations mergeToolChainLists(const QList<ToolChain *> &systemFileTcs,
const QList<ToolChain *> &userFileTcs,
const QList<ToolChain *> &autodetectedTcs)
{
const QList<ToolChain *> manualUserTcs
= Utils::filtered(userFileTcs, [](ToolChain *t) { return !t->isAutoDetected(); });
// Remove systemFileTcs from autodetectedUserTcs based on id-matches:
const QList<ToolChain *> autodetectedUserFileTcs
= Utils::filtered(userFileTcs, &ToolChain::isAutoDetected);
const QList<ToolChain *> autodetectedUserTcs = subtractById(autodetectedUserFileTcs, systemFileTcs);
// Calculate a set of Tcs that were detected before (and saved to userFile) and that
// got re-detected again. Take the userTcs (to keep Ids) over the same in autodetectedTcs.
const QList<ToolChain *> redetectedUserTcs
= intersectByEqual(autodetectedUserTcs, autodetectedTcs);
// Remove redetected tcs from autodetectedUserTcs:
const QList<ToolChain *> notRedetectedUserTcs
= subtractByPointerEqual(autodetectedUserTcs, redetectedUserTcs);
// Remove redetected tcs from autodetectedTcs:
const QList<ToolChain *> newlyAutodetectedTcs
= subtractByEqual(autodetectedTcs, redetectedUserTcs);
const QList<ToolChain *> notRedetectedButValidUserTcs
= Utils::filtered(notRedetectedUserTcs, &ToolChain::isValid);
const QList<ToolChain *> validManualUserTcs
= Utils::filtered(manualUserTcs, &ToolChain::isValid);
ToolChainOperations result;
result.toDemote = notRedetectedButValidUserTcs;
result.toRegister = result.toDemote + systemFileTcs + redetectedUserTcs + newlyAutodetectedTcs
+ validManualUserTcs;
result.toDelete = makeUnique(subtractByPointerEqual(systemFileTcs + userFileTcs + autodetectedTcs,
result.toRegister));
return result;
}
void ToolChainManager::restoreToolChains() void ToolChainManager::restoreToolChains()
{ {
QTC_ASSERT(!d->m_writer, return); QTC_ASSERT(!d->m_writer, return);
d->m_writer = d->m_writer =
new PersistentSettingsWriter(settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)), QLatin1String("QtCreatorToolChains")); new PersistentSettingsWriter(settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)),
QLatin1String("QtCreatorToolChains"));
QList<ToolChain *> tcsToRegister;
QList<ToolChain *> tcsToCheck;
// read all tool chains from SDK // read all tool chains from SDK
QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName()); const QList<ToolChain *> systemFileTcs = readSystemFileToolChains();
QList<ToolChain *> readTcs =
restoreFromFile(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(TOOLCHAIN_FILENAME)));
// make sure we mark these as autodetected!
foreach (ToolChain *tc, readTcs)
tc->setDetection(ToolChain::AutoDetection);
tcsToRegister = readTcs; // SDK TCs are always considered to be up-to-date, so no need to
// recheck them.
// read all tool chains from user file. // read all tool chains from user file.
// Read legacy settings once and keep them around... const QList<ToolChain *> userFileTcs
FileName fileName = settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)); = restoreFromFile(settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)));
if (!fileName.exists())
fileName = settingsFileName(QLatin1String(LEGACY_TOOLCHAIN_FILENAME));
readTcs = restoreFromFile(fileName);
foreach (ToolChain *tc, readTcs) { // Autodetect: Pass autodetected toolchains from user file so the information can be reused:
if (tc->isAutoDetected()) const QList<ToolChain *> autodetectedUserFileTcs
tcsToCheck.append(tc); = Utils::filtered(userFileTcs, &ToolChain::isAutoDetected);
else const QList<ToolChain *> autodetectedTcs = autoDetectToolChains(autodetectedUserFileTcs);
tcsToRegister.append(tc);
}
readTcs.clear();
// Remove TCs configured by the SDK: // merge tool chains and register those that we need to keep:
foreach (ToolChain *tc, tcsToRegister) { ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs);
for (int i = tcsToCheck.count() - 1; i >= 0; --i) {
if (tcsToCheck.at(i)->id() == tc->id()) {
delete tcsToCheck.at(i);
tcsToCheck.removeAt(i);
}
}
}
// Then auto detect // Process ops:
QList<ToolChain *> detectedTcs = tcsToCheck; foreach (ToolChain *tc, ops.toDemote)
QList<ToolChainFactory *> factories = ExtensionSystem::PluginManager::getObjects<ToolChainFactory>(); tc->setDetection(ToolChain::ManualDetection);
foreach (ToolChainFactory *f, factories)
detectedTcs.append(f->autoDetect(tcsToCheck));
// Find/update autodetected tool chains: foreach (ToolChain *tc, ops.toRegister)
ToolChain *toStore = 0;
foreach (ToolChain *currentDetected, detectedTcs) {
toStore = currentDetected;
// Check whether we had this TC stored and prefer the old one with the old id, marked
// as auto-detection.
for (int i = 0; i < tcsToCheck.count(); ++i) {
if (tcsToCheck.at(i) == currentDetected) {
tcsToCheck.removeAt(i);
break;
} else if (*(tcsToCheck.at(i)) == *currentDetected) {
toStore = tcsToCheck.at(i);
toStore->setDetection(ToolChain::AutoDetection);
tcsToCheck.removeAt(i);
delete currentDetected;
break;
}
}
tcsToRegister += toStore;
}
// Keep toolchains that were not rediscovered but are still executable and delete the rest
foreach (ToolChain *tc, tcsToCheck) {
if (!tc->isValid()) {
qWarning() << QString::fromLatin1("ToolChain \"%1\" (%2) dropped since it is not valid")
.arg(tc->displayName()).arg(QString::fromUtf8(tc->id()));
delete tc;
} else {
tc->setDetection(ToolChain::ManualDetection); // "demote" to manual toolchain
tcsToRegister += tc;
}
}
// Store manual tool chains
foreach (ToolChain *tc, tcsToRegister)
registerToolChain(tc); registerToolChain(tc);
qDeleteAll(ops.toDelete);
emit m_instance->toolChainsLoaded(); emit m_instance->toolChainsLoaded();
} }
QList<ToolChain *> ToolChainManager::readSystemFileToolChains()
{
QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName());
QList<ToolChain *> systemTcs
= restoreFromFile(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(TOOLCHAIN_FILENAME)));
foreach (ToolChain *tc, systemTcs)
tc->setDetection(ToolChain::AutoDetection);
return systemTcs;
}
void ToolChainManager::saveToolChains() void ToolChainManager::saveToolChains()
{ {
QVariantMap data; QVariantMap data;
@@ -360,3 +407,193 @@ void ToolChainManager::deregisterToolChain(ToolChain *tc)
} }
} // namespace ProjectExplorer } // namespace ProjectExplorer
#ifdef WITH_TESTS
#include "projectexplorer.h"
#include "headerpath.h"
#include <QSet>
#include <QTest>
namespace ProjectExplorer {
typedef QList<ToolChain *> TCList;
class TTC : public ToolChain
{
public:
TTC(ToolChain::Detection d, const QByteArray &t, bool v = true) :
ToolChain("TestToolChainType", d),
token(t),
m_valid(v)
{ m_toolChains.append(this); }
static QList<TTC *> toolChains();
static bool hasToolChains() { return !m_toolChains.isEmpty(); }
QString typeDisplayName() const override { return QLatin1String("Test Tool Chain"); }
Abi targetAbi() const override { return Abi::hostAbi(); }
bool isValid() const override { return m_valid; }
QByteArray predefinedMacros(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return QByteArray(); }
CompilerFlags compilerFlags(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return NoFlags; }
WarningFlags warningFlags(const QStringList &cflags) const override { Q_UNUSED(cflags); return 0; }
QList<HeaderPath> systemHeaderPaths(const QStringList &cxxflags, const FileName &sysRoot) const override
{ Q_UNUSED(cxxflags); Q_UNUSED(sysRoot); return QList<HeaderPath>(); }
void addToEnvironment(Environment &env) const override { Q_UNUSED(env); }
QString makeCommand(const Environment &env) const override { Q_UNUSED(env); return QLatin1String("make"); }
FileName compilerCommand() const override { return Utils::FileName::fromString(QLatin1String("/tmp/test/gcc")); }
IOutputParser *outputParser() const override { return 0; }
ToolChainConfigWidget *configurationWidget() override { return 0; }
TTC *clone() const override { return new TTC(*this); }
bool operator ==(const ToolChain &other) const override {
if (!ToolChain::operator==(other))
return false;
return static_cast<const TTC *>(&other)->token == token;
}
QByteArray token;
private:
TTC(const TTC &other) :
ToolChain(other)
{ token = other.token; }
bool m_valid;
static QList<TTC *> m_toolChains;
// ToolChain interface
public:
};
QList<TTC *> TTC::m_toolChains;
} // namespace ProjectExplorer
Q_DECLARE_METATYPE(ProjectExplorer::ToolChain *)
namespace ProjectExplorer {
void ProjectExplorerPlugin::testToolChainManager_data()
{
QTest::addColumn<TCList>("system");
QTest::addColumn<TCList>("user");
QTest::addColumn<TCList>("autodetect");
QTest::addColumn<TCList>("toDemote");
QTest::addColumn<TCList>("toRegister");
TTC *system1 = 0;
TTC *system1c = 0;
TTC *system2 = 0;
TTC *system3i = 0;
TTC *user1 = 0;
TTC *user1c = 0;
TTC *user3i = 0;
TTC *user2 = 0;
TTC *auto1 = 0;
TTC *auto1c = 0;
TTC *auto1_2 = 0;
TTC *auto2 = 0;
TTC *auto3i = 0;
if (!TTC::hasToolChains()) {
system1 = new TTC(ToolChain::AutoDetection, "system1"); Q_UNUSED(system1);
system1c = system1->clone(); Q_UNUSED(system1c);
system2 = new TTC(ToolChain::AutoDetection, "system2"); Q_UNUSED(system2);
system3i = new TTC(ToolChain::AutoDetection, "system3", false); Q_UNUSED(system3i);
user1 = new TTC(ToolChain::ManualDetection, "user1"); Q_UNUSED(user1);
user1c = user1->clone(); Q_UNUSED(user1c);
user2 = new TTC(ToolChain::ManualDetection, "user2"); Q_UNUSED(user2);
user3i = new TTC(ToolChain::ManualDetection, "user3", false); Q_UNUSED(user3i);
auto1 = new TTC(ToolChain::AutoDetectionFromSettings, "auto1"); Q_UNUSED(auto1);
auto1c = auto1->clone(); Q_UNUSED(auto1c);
auto1_2 = new TTC(ToolChain::AutoDetectionFromSettings, "auto1"); Q_UNUSED(auto1_2);
auto2 = new TTC(ToolChain::AutoDetectionFromSettings, "auto2"); Q_UNUSED(auto2);
auto3i = new TTC(ToolChain::AutoDetectionFromSettings, "auto3", false); Q_UNUSED(auto3i);
}
QTest::newRow("no toolchains")
<< (TCList()) << (TCList()) << (TCList())
<< (TCList()) << (TCList());
QTest::newRow("System: system, no user")
<< (TCList() << system1) << (TCList()) << (TCList())
<< (TCList()) << (TCList() << system1);
QTest::newRow("System: system, user")
<< (TCList() << system1) << (TCList() << system1) << (TCList())
<< (TCList()) << (TCList() << system1);
QTest::newRow("System: no system, user") // keep, the user tool chain as it is still found
<< (TCList()) << (TCList() << system1) << (TCList())
<< (TCList() << system1) << (TCList() << system1);
QTest::newRow("System: no system, invalid user")
<< (TCList()) << (TCList() << system3i) << (TCList())
<< (TCList()) << (TCList());
QTest::newRow("Auto: no auto, user")
<< (TCList()) << (TCList() << auto1) << (TCList())
<< (TCList() << auto1) << (TCList() << auto1);
QTest::newRow("Auto: auto, no user")
<< (TCList()) << (TCList()) << (TCList() << auto1)
<< (TCList()) << (TCList() << auto1);
QTest::newRow("Auto: auto, user")
<< (TCList()) << (TCList() << auto1) << (TCList() << auto1)
<< (TCList()) << (TCList() << auto1);
QTest::newRow("Auto: auto-redetect, user")
<< (TCList()) << (TCList() << auto1) << (TCList() << auto1_2)
<< (TCList()) << (TCList() << auto1);
QTest::newRow("Auto: (no) auto, invalid user")
<< (TCList()) << (TCList() << auto3i) << (TCList())
<< (TCList()) << (TCList());
QTest::newRow("Delete invalid user")
<< (TCList()) << (TCList() << user3i) << (TCList())
<< (TCList()) << (TCList());
QTest::newRow("one of everything")
<< (TCList() << system1) << (TCList() << user1) << (TCList() << auto1)
<< (TCList()) << (TCList() << system1 << user1 << auto1);
}
void ProjectExplorerPlugin::testToolChainManager()
{
QFETCH(TCList, system);
QFETCH(TCList, user);
QFETCH(TCList, autodetect);
QFETCH(TCList, toRegister);
QFETCH(TCList, toDemote);
ToolChainOperations ops = mergeToolChainLists(system, user, autodetect);
QSet<ToolChain *> expToRegister = QSet<ToolChain *>::fromList(toRegister);
QSet<ToolChain *> expToDemote = QSet<ToolChain *>::fromList(toDemote);
QSet<ToolChain *> actToRegister = QSet<ToolChain *>::fromList(ops.toRegister);
QSet<ToolChain *> actToDemote = QSet<ToolChain *>::fromList(ops.toDemote);
QSet<ToolChain *> actToDelete = QSet<ToolChain *>::fromList(ops.toDelete);
QCOMPARE(actToRegister.count(), ops.toRegister.count()); // no dups!
QCOMPARE(actToDemote.count(), ops.toDemote.count()); // no dups!
QCOMPARE(actToDelete.count(), ops.toDelete.count()); // no dups!
QSet<ToolChain *> tmp = actToRegister;
tmp.intersect(actToDemote);
QCOMPARE(tmp, actToDemote); // all toDemote are in toRegister
tmp = actToRegister;
tmp.intersect(actToDelete);
QVERIFY(tmp.isEmpty()); // Nothing that needs to be registered is to be deleted
tmp = actToRegister;
tmp.unite(actToDelete);
QCOMPARE(tmp, QSet<ToolChain *>::fromList(system + user + autodetect)); // All input is accounted for
QCOMPARE(expToRegister, actToRegister);
QCOMPARE(expToDemote, actToDemote);
QCOMPARE(QSet<ToolChain *>::fromList(system + user + autodetect),
QSet<ToolChain *>::fromList(ops.toRegister + ops.toDemote + ops.toDelete));
}
} // namespace ProjectExplorer
#endif // WITH_TESTS

View File

@@ -87,6 +87,9 @@ private:
// Make sure the this is only called after all // Make sure the this is only called after all
// Tool chain Factories are registered! // Tool chain Factories are registered!
static void restoreToolChains(); static void restoreToolChains();
static QList<ToolChain *> readSystemFileToolChains();
static void notifyAboutUpdate(ToolChain *); static void notifyAboutUpdate(ToolChain *);
friend class ProjectExplorerPlugin; // for constructor friend class ProjectExplorerPlugin; // for constructor

View File

@@ -33,6 +33,7 @@
#include "msvcparser.h" #include "msvcparser.h"
#include "projectexplorerconstants.h" #include "projectexplorerconstants.h"
#include <utils/algorithm.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDir> #include <QDir>
@@ -352,10 +353,33 @@ WinCEToolChainFactory::WinCEToolChainFactory()
setDisplayName(tr("WinCE")); setDisplayName(tr("WinCE"));
} }
static ToolChain *findOrCreateToolChain(const QList<ToolChain *> &alreadyKnown,
const QString &name, const Abi &abi,
const QString &vcvarsBat, const QString &msvcVer,
const QString &ceVer, const QString &binPath,
const QString &includePath, const QString &libPath,
ToolChain::Detection d = ToolChain::ManualDetection)
{
ToolChain *tc
= Utils::findOrDefault(alreadyKnown, [&](ToolChain *tc) -> bool {
if (tc->typeId() != Constants::WINCE_TOOLCHAIN_TYPEID)
return false;
auto cetc = static_cast<WinCEToolChain *>(tc);
return cetc->targetAbi() == abi
&& cetc->varsBat() == vcvarsBat
&& cetc->msvcVer() == msvcVer
&& cetc->ceVer() == ceVer
&& cetc->binPath() == binPath
&& cetc->includePath() == includePath
&& cetc->libPath() == libPath;
});
if (!tc)
tc = new WinCEToolChain(name, abi, vcvarsBat, msvcVer, ceVer, binPath, includePath, libPath, d);
return tc;
}
QList<ToolChain *> WinCEToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) QList<ToolChain *> WinCEToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{ {
Q_UNUSED(alreadyKnown);
QList<ToolChain *> results; QList<ToolChain *> results;
// 1) Installed WinCEs // 1) Installed WinCEs
@@ -398,16 +422,16 @@ QList<ToolChain *> WinCEToolChainFactory::autoDetect(const QList<ToolChain *> &a
QString ceVer; QString ceVer;
if (parseSDK(platformReader, theArch, thePlat, ceVer, binPath, includePath, libPath)) { if (parseSDK(platformReader, theArch, thePlat, ceVer, binPath, includePath, libPath)) {
WinCEToolChain *pChain = new WinCEToolChain(thePlat, results.append(findOrCreateToolChain(alreadyKnown,
Abi(theArch, Abi::WindowsOS, Abi::WindowsCEFlavor, Abi::PEFormat, 32), thePlat,
vcvars32bat, Abi(theArch, Abi::WindowsOS, Abi::WindowsCEFlavor, Abi::PEFormat, 32),
msvcVer, vcvars32bat,
ceVer, msvcVer,
binPath, ceVer,
includePath, binPath,
libPath, includePath,
ToolChain::AutoDetection); libPath,
results.append(pChain); ToolChain::AutoDetection));
} }
} }
} }

View File

@@ -57,8 +57,13 @@ public:
QString typeDisplayName() const override; QString typeDisplayName() const override;
QString msvcVer() const { return m_msvcVer; }
QString ceVer() const; QString ceVer() const;
QString binPath() const { return m_binPath; }
QString includePath() const { return m_includePath; }
QString libPath() const { return m_libPath; }
QVariantMap toMap() const override; QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override; bool fromMap(const QVariantMap &data) override;

View File

@@ -31,7 +31,6 @@
#include "qbsbuildconfiguration.h" #include "qbsbuildconfiguration.h"
#include "qbsbuildconfigurationwidget.h" #include "qbsbuildconfigurationwidget.h"
#include "qbsbuildinfo.h"
#include "qbsbuildstep.h" #include "qbsbuildstep.h"
#include "qbscleanstep.h" #include "qbscleanstep.h"
#include "qbsinstallstep.h" #include "qbsinstallstep.h"
@@ -41,6 +40,7 @@
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <projectexplorer/buildinfo.h>
#include <projectexplorer/buildsteplist.h> #include <projectexplorer/buildsteplist.h>
#include <projectexplorer/kit.h> #include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
@@ -374,10 +374,10 @@ bool QbsBuildConfigurationFactory::canHandle(const Target *t) const
BuildInfo *QbsBuildConfigurationFactory::createBuildInfo(const Kit *k, BuildInfo *QbsBuildConfigurationFactory::createBuildInfo(const Kit *k,
BuildConfiguration::BuildType type) const BuildConfiguration::BuildType type) const
{ {
QbsBuildInfo *info = new QbsBuildInfo(this); auto info = new ProjectExplorer::BuildInfo(this);
info->typeName = tr("Build"); info->typeName = tr("Build");
info->kitId = k->id(); info->kitId = k->id();
info->type = type; info->buildType = type;
return info; return info;
} }
@@ -405,10 +405,11 @@ int QbsBuildConfigurationFactory::priority(const Kit *k, const QString &projectP
} }
static Utils::FileName defaultBuildDirectory(const QString &projectFilePath, const Kit *k, static Utils::FileName defaultBuildDirectory(const QString &projectFilePath, const Kit *k,
const QString &bcName) const QString &bcName,
BuildConfiguration::BuildType buildType)
{ {
const QString projectName = QFileInfo(projectFilePath).completeBaseName(); const QString projectName = QFileInfo(projectFilePath).completeBaseName();
ProjectMacroExpander expander(projectName, k, bcName); ProjectMacroExpander expander(projectName, k, bcName, buildType);
QString projectDir = Project::projectDirectory(Utils::FileName::fromString(projectFilePath)).toString(); QString projectDir = Project::projectDirectory(Utils::FileName::fromString(projectFilePath)).toString();
QString buildPath = expander.expand(Core::DocumentManager::buildDirectory()); QString buildPath = expander.expand(Core::DocumentManager::buildDirectory());
return Utils::FileName::fromString(Utils::FileUtils::resolvePath(projectDir, buildPath)); return Utils::FileName::fromString(Utils::FileUtils::resolvePath(projectDir, buildPath));
@@ -422,14 +423,18 @@ QList<BuildInfo *> QbsBuildConfigurationFactory::availableSetups(const Kit *k, c
//: The name of the debug build configuration created by default for a qbs project. //: The name of the debug build configuration created by default for a qbs project.
info->displayName = tr("Debug"); info->displayName = tr("Debug");
//: Non-ASCII characters in directory suffix may cause build issues. //: Non-ASCII characters in directory suffix may cause build issues.
info->buildDirectory = defaultBuildDirectory(projectPath, k, tr("Debug", "Shadow build directory suffix")); info->buildDirectory
= defaultBuildDirectory(projectPath, k, tr("Debug", "Shadow build directory suffix"),
info->buildType);
result << info; result << info;
info = createBuildInfo(k, BuildConfiguration::Release); info = createBuildInfo(k, BuildConfiguration::Release);
//: The name of the release build configuration created by default for a qbs project. //: The name of the release build configuration created by default for a qbs project.
info->displayName = tr("Release"); info->displayName = tr("Release");
//: Non-ASCII characters in directory suffix may cause build issues. //: Non-ASCII characters in directory suffix may cause build issues.
info->buildDirectory = defaultBuildDirectory(projectPath, k, tr("Release", "Shadow build directory suffix")); info->buildDirectory
= defaultBuildDirectory(projectPath, k, tr("Release", "Shadow build directory suffix"),
info->buildType);
result << info; result << info;
return result; return result;
@@ -441,18 +446,16 @@ BuildConfiguration *QbsBuildConfigurationFactory::create(Target *parent, const B
QTC_ASSERT(info->kitId == parent->kit()->id(), return 0); QTC_ASSERT(info->kitId == parent->kit()->id(), return 0);
QTC_ASSERT(!info->displayName.isEmpty(), return 0); QTC_ASSERT(!info->displayName.isEmpty(), return 0);
const QbsBuildInfo *qbsInfo = static_cast<const QbsBuildInfo *>(info);
QVariantMap configData; QVariantMap configData;
configData.insert(QLatin1String(Constants::QBS_CONFIG_VARIANT_KEY), configData.insert(QLatin1String(Constants::QBS_CONFIG_VARIANT_KEY),
(qbsInfo->type == BuildConfiguration::Debug) (info->buildType == BuildConfiguration::Debug)
? QLatin1String(Constants::QBS_VARIANT_DEBUG) ? QLatin1String(Constants::QBS_VARIANT_DEBUG)
: QLatin1String(Constants::QBS_VARIANT_RELEASE)); : QLatin1String(Constants::QBS_VARIANT_RELEASE));
Utils::FileName buildDir = info->buildDirectory; Utils::FileName buildDir = info->buildDirectory;
if (buildDir.isEmpty()) if (buildDir.isEmpty())
buildDir = defaultBuildDirectory(parent->project()->projectDirectory().toString(), buildDir = defaultBuildDirectory(parent->project()->projectDirectory().toString(),
parent->kit(), info->displayName); parent->kit(), info->displayName, info->buildType);
BuildConfiguration *bc BuildConfiguration *bc
= QbsBuildConfiguration::setup(parent, info->displayName, info->displayName, = QbsBuildConfiguration::setup(parent, info->displayName, info->displayName,

View File

@@ -1,53 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QBSBUILDINFO_H
#define QBSBUILDINFO_H
#include "qbsbuildconfiguration.h"
#include <projectexplorer/buildinfo.h>
#include <qtsupport/baseqtversion.h>
namespace QbsProjectManager {
namespace Internal {
class QbsBuildInfo : public ProjectExplorer::BuildInfo
{
public:
QbsBuildInfo(const QbsBuildConfigurationFactory *f) : ProjectExplorer::BuildInfo(f) { }
ProjectExplorer::BuildConfiguration::BuildType type;
};
} // namespace Internal
} // namespace QbsProjectManager
#endif // QBSBUILDINFO_H

View File

@@ -39,6 +39,7 @@
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/qtsupportconstants.h> #include <qtsupport/qtsupportconstants.h>
#include <resourceeditor/resourcenode.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -484,10 +485,11 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root, const qbs::Gro
foreach (FileTreeNode *c, fileTree->children) { foreach (FileTreeNode *c, fileTree->children) {
Utils::FileName path = Utils::FileName::fromString(c->path()); Utils::FileName path = Utils::FileName::fromString(c->path());
const ProjectExplorer::FileType newFileType = fileType(group, c->path());
const bool isQrcFile = newFileType == ProjectExplorer::ResourceType;
// Handle files: // Handle files:
if (c->isFile()) { if (c->isFile() && !isQrcFile) {
const ProjectExplorer::FileType newFileType = fileType(group, c->path());
ProjectExplorer::FileNode *fn = 0; ProjectExplorer::FileNode *fn = 0;
foreach (ProjectExplorer::FileNode *f, root->fileNodes()) { foreach (ProjectExplorer::FileNode *f, root->fileNodes()) {
// There can be one match only here! // There can be one match only here!
@@ -514,10 +516,15 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root, const qbs::Gro
fn = f; fn = f;
break; break;
} }
using ResourceEditor::ResourceTopLevelNode;
if (!fn) { if (!fn) {
fn = new QbsFolderNode(Utils::FileName::fromString(c->path()), if (isQrcFile) {
ProjectExplorer::FolderNodeType, fn = new ResourceTopLevelNode(Utils::FileName::fromString(c->path()), root);
displayNameFromPath(c->path(), baseDir)); } else {
fn = new QbsFolderNode(Utils::FileName::fromString(c->path()),
ProjectExplorer::FolderNodeType,
displayNameFromPath(c->path(), baseDir));
}
root->addFolderNodes(QList<FolderNode *>() << fn); root->addFolderNodes(QList<FolderNode *>() << fn);
} else { } else {
foldersToRemove.removeOne(fn); foldersToRemove.removeOne(fn);
@@ -526,7 +533,11 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root, const qbs::Gro
fn->setDisplayName(displayNameFromPath(c->path(), baseDir)); fn->setDisplayName(displayNameFromPath(c->path(), baseDir));
} }
setupFolder(fn, group, c, c->path(), updateExisting); if (isQrcFile)
static_cast<ResourceTopLevelNode *>(fn)->update();
else
setupFolder(fn, group, c, c->path(), updateExisting);
} }
} }
root->removeFileNodes(filesToRemove); root->removeFileNodes(filesToRemove);

View File

@@ -23,7 +23,6 @@ HEADERS = \
propertyprovider.h \ propertyprovider.h \
qbsbuildconfiguration.h \ qbsbuildconfiguration.h \
qbsbuildconfigurationwidget.h \ qbsbuildconfigurationwidget.h \
qbsbuildinfo.h \
qbsbuildstep.h \ qbsbuildstep.h \
qbscleanstep.h \ qbscleanstep.h \
qbsdeployconfigurationfactory.h \ qbsdeployconfigurationfactory.h \

View File

@@ -41,6 +41,7 @@ QtcPlugin {
Depends { name: "ProjectExplorer" } Depends { name: "ProjectExplorer" }
Depends { name: "Core" } Depends { name: "Core" }
Depends { name: "CppTools" } Depends { name: "CppTools" }
Depends { name: "ResourceEditor" }
Depends { name: "QtSupport" } Depends { name: "QtSupport" }
Depends { name: "QmlJSTools" } Depends { name: "QmlJSTools" }
@@ -68,7 +69,6 @@ QtcPlugin {
"qbsbuildconfiguration.h", "qbsbuildconfiguration.h",
"qbsbuildconfigurationwidget.cpp", "qbsbuildconfigurationwidget.cpp",
"qbsbuildconfigurationwidget.h", "qbsbuildconfigurationwidget.h",
"qbsbuildinfo.h",
"qbsbuildstep.cpp", "qbsbuildstep.cpp",
"qbsbuildstep.h", "qbsbuildstep.h",
"qbsbuildstepconfigwidget.ui", "qbsbuildstepconfigwidget.ui",

View File

@@ -8,4 +8,5 @@ QTC_PLUGIN_DEPENDS += \
projectexplorer \ projectexplorer \
cpptools \ cpptools \
qtsupport \ qtsupport \
qmljstools qmljstools \
resourceeditor

View File

@@ -75,13 +75,15 @@ namespace QmakeProjectManager {
// Helpers: // Helpers:
// -------------------------------------------------------------------- // --------------------------------------------------------------------
QString QmakeBuildConfiguration::shadowBuildDirectory(const QString &proFilePath, const Kit *k, const QString &suffix) QString QmakeBuildConfiguration::shadowBuildDirectory(const QString &proFilePath, const Kit *k,
const QString &suffix,
BuildConfiguration::BuildType buildType)
{ {
if (proFilePath.isEmpty()) if (proFilePath.isEmpty())
return QString(); return QString();
const QString projectName = QFileInfo(proFilePath).completeBaseName(); const QString projectName = QFileInfo(proFilePath).completeBaseName();
ProjectMacroExpander expander(projectName, k, suffix); ProjectMacroExpander expander(projectName, k, suffix, buildType);
QString projectDir = Project::projectDirectory(FileName::fromString(proFilePath)).toString(); QString projectDir = Project::projectDirectory(FileName::fromString(proFilePath)).toString();
QString buildPath = expander.expand(Core::DocumentManager::buildDirectory()); QString buildPath = expander.expand(Core::DocumentManager::buildDirectory());
return FileUtils::resolvePath(projectDir, buildPath); return FileUtils::resolvePath(projectDir, buildPath);
@@ -89,9 +91,11 @@ QString QmakeBuildConfiguration::shadowBuildDirectory(const QString &proFilePath
static Utils::FileName defaultBuildDirectory(const QString &projectPath, static Utils::FileName defaultBuildDirectory(const QString &projectPath,
const ProjectExplorer::Kit *k, const ProjectExplorer::Kit *k,
const QString &suffix) const QString &suffix,
BuildConfiguration::BuildType type)
{ {
return Utils::FileName::fromString(QmakeBuildConfiguration::shadowBuildDirectory(projectPath, k, suffix)); return Utils::FileName::fromString(QmakeBuildConfiguration::shadowBuildDirectory(projectPath, k,
suffix, type));
} }
const char QMAKE_BC_ID[] = "Qt4ProjectManager.Qt4BuildConfiguration"; const char QMAKE_BC_ID[] = "Qt4ProjectManager.Qt4BuildConfiguration";
@@ -597,9 +601,9 @@ QmakeBuildInfo *QmakeBuildConfigurationFactory::createBuildInfo(const Kit *k,
info->buildDirectory = Utils::FileName::fromString(absoluteBuildPath); info->buildDirectory = Utils::FileName::fromString(absoluteBuildPath);
} else { } else {
info->buildDirectory = defaultBuildDirectory(projectPath, k, suffix); info->buildDirectory = defaultBuildDirectory(projectPath, k, suffix, type);
} }
info->type = type; info->buildType = type;
return info; return info;
} }
@@ -654,7 +658,7 @@ void QmakeBuildConfigurationFactory::configureBuildConfiguration(Target *parent,
BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(parent->kit()); BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(parent->kit());
BaseQtVersion::QmakeBuildConfigs config = version->defaultBuildConfig(); BaseQtVersion::QmakeBuildConfigs config = version->defaultBuildConfig();
if (qmakeInfo->type == BuildConfiguration::Debug) if (qmakeInfo->buildType == BuildConfiguration::Debug)
config |= QtSupport::BaseQtVersion::DebugBuild; config |= QtSupport::BaseQtVersion::DebugBuild;
else else
config &= ~QtSupport::BaseQtVersion::DebugBuild; config &= ~QtSupport::BaseQtVersion::DebugBuild;
@@ -690,7 +694,7 @@ void QmakeBuildConfigurationFactory::configureBuildConfiguration(Target *parent,
Utils::FileName directory = qmakeInfo->buildDirectory; Utils::FileName directory = qmakeInfo->buildDirectory;
if (directory.isEmpty()) { if (directory.isEmpty()) {
directory = defaultBuildDirectory(parent->project()->projectFilePath().toString(), directory = defaultBuildDirectory(parent->project()->projectFilePath().toString(),
parent->kit(), qmakeInfo->displayName); parent->kit(), qmakeInfo->displayName, bc->buildType());
} }
bc->setBuildDirectory(directory); bc->setBuildDirectory(directory);

View File

@@ -70,7 +70,7 @@ public:
/// suffix should be unique /// suffix should be unique
static QString shadowBuildDirectory(const QString &profilePath, const ProjectExplorer::Kit *k, static QString shadowBuildDirectory(const QString &profilePath, const ProjectExplorer::Kit *k,
const QString &suffix); const QString &suffix, BuildConfiguration::BuildType type);
/// \internal for qmakestep /// \internal for qmakestep
// used by qmake step to notify that the qmake args have changed // used by qmake step to notify that the qmake args have changed

View File

@@ -46,17 +46,13 @@ class QmakeBuildInfo : public ProjectExplorer::BuildInfo
public: public:
QmakeBuildInfo(const QmakeBuildConfigurationFactory *f) : ProjectExplorer::BuildInfo(f) { } QmakeBuildInfo(const QmakeBuildConfigurationFactory *f) : ProjectExplorer::BuildInfo(f) { }
ProjectExplorer::BuildConfiguration::BuildType type = ProjectExplorer::BuildConfiguration::Unknown;
QString additionalArguments; QString additionalArguments;
QString makefile; QString makefile;
QMakeStepConfig config; QMakeStepConfig config;
bool operator==(const QmakeBuildInfo &o) { bool operator==(const QmakeBuildInfo &o)
return displayName == o.displayName {
&& typeName == o.typeName return ProjectExplorer::BuildInfo::operator==(o)
&& buildDirectory == o.buildDirectory
&& kitId == o.kitId
&& type == o.type
&& additionalArguments == o.additionalArguments && additionalArguments == o.additionalArguments
&& config == o.config; && config == o.config;
} }

View File

@@ -1267,10 +1267,16 @@ bool QmakePriFileNode::renameFile(const QString &oldName,
QDir priFileDir = QDir(m_qmakeProFileNode->m_projectDir); QDir priFileDir = QDir(m_qmakeProFileNode->m_projectDir);
QStringList notChanged = ProWriter::removeFiles(includeFile, &lines, priFileDir, QStringList notChanged = ProWriter::removeFiles(includeFile, &lines, priFileDir,
QStringList(oldName), varNamesForRemoving()); QStringList(oldName), varNamesForRemoving());
if (!notChanged.isEmpty()) {
includeFile->deref(); includeFile->deref();
if (!notChanged.isEmpty())
return false; return false;
}
// We need to re-parse here: The file has changed.
QMakeParser parser(0, 0, 0);
includeFile = parser.parsedProBlock(lines.join(QLatin1Char('\n')),
m_projectFilePath.toString(), 1, QMakeParser::FullGrammar);
QTC_ASSERT(includeFile, return false); // The file should still be valid after what we did.
ProWriter::addFiles(includeFile, &lines, ProWriter::addFiles(includeFile, &lines,
QStringList(newName), QStringList(newName),

View File

@@ -54,7 +54,8 @@ QmakeProjectConfigWidget::QmakeProjectConfigWidget(QmakeBuildConfiguration *bc)
m_defaultShadowBuildDir m_defaultShadowBuildDir
= QmakeBuildConfiguration::shadowBuildDirectory(bc->target()->project()->projectFilePath().toString(), = QmakeBuildConfiguration::shadowBuildDirectory(bc->target()->project()->projectFilePath().toString(),
bc->target()->kit(), bc->target()->kit(),
Utils::FileUtils::qmakeFriendlyName(bc->displayName())); Utils::FileUtils::qmakeFriendlyName(bc->displayName()),
bc->buildType());
QVBoxLayout *vbox = new QVBoxLayout(this); QVBoxLayout *vbox = new QVBoxLayout(this);
vbox->setMargin(0); vbox->setMargin(0);

View File

@@ -220,10 +220,10 @@ QList<BuildInfo *> QmakeProjectImporter::import(const FileName &importPath, bool
QmakeBuildInfo *info = new QmakeBuildInfo(factory); QmakeBuildInfo *info = new QmakeBuildInfo(factory);
BaseQtVersion::QmakeBuildConfigs buildConfig = parse.effectiveBuildConfig(version->defaultBuildConfig()); BaseQtVersion::QmakeBuildConfigs buildConfig = parse.effectiveBuildConfig(version->defaultBuildConfig());
if (buildConfig & BaseQtVersion::DebugBuild) { if (buildConfig & BaseQtVersion::DebugBuild) {
info->type = BuildConfiguration::Debug; info->buildType = BuildConfiguration::Debug;
info->displayName = QCoreApplication::translate("QmakeProjectManager::Internal::QmakeProjectImporter", "Debug"); info->displayName = QCoreApplication::translate("QmakeProjectManager::Internal::QmakeProjectImporter", "Debug");
} else { } else {
info->type = BuildConfiguration::Release; info->buildType = BuildConfiguration::Release;
info->displayName = QCoreApplication::translate("QmakeProjectManager::Internal::QmakeProjectImporter", "Release"); info->displayName = QCoreApplication::translate("QmakeProjectManager::Internal::QmakeProjectImporter", "Release");
} }
info->kitId = k->id(); info->kitId = k->id();
@@ -264,7 +264,8 @@ QStringList QmakeProjectImporter::importCandidates(const FileName &projectPath)
candidates << pfi.absolutePath(); candidates << pfi.absolutePath();
foreach (Kit *k, KitManager::kits()) { foreach (Kit *k, KitManager::kits()) {
QFileInfo fi(QmakeBuildConfiguration::shadowBuildDirectory(projectPath.toString(), k, QString())); QFileInfo fi(QmakeBuildConfiguration::shadowBuildDirectory(projectPath.toString(), k,
QString(), BuildConfiguration::Unknown));
const QString baseDir = fi.absolutePath(); const QString baseDir = fi.absolutePath();
foreach (const QString &dir, QDir(baseDir).entryList()) { foreach (const QString &dir, QDir(baseDir).entryList()) {

View File

@@ -551,8 +551,8 @@ void gotoImplementation(const SelectionContext &/*selectionState*/)
QList<QmlJSEditor::FindReferences::Usage> usages = QmlJSEditor::FindReferences::findUsageOfType(fileName, typeName); QList<QmlJSEditor::FindReferences::Usage> usages = QmlJSEditor::FindReferences::findUsageOfType(fileName, typeName);
if (usages.isEmpty()) { if (usages.isEmpty()) {
QString title = QCoreApplication::translate("ModelNodeOperations", "Goto implementation"); QString title = QCoreApplication::translate("ModelNodeOperations", "Go to Implementation");
QString description = QCoreApplication::translate("ModelNodeOperations", "Cannot find any implementation."); QString description = QCoreApplication::translate("ModelNodeOperations", "Cannot find an implementation.");
Core::AsynchronousMessageBox::warning(title, description); Core::AsynchronousMessageBox::warning(title, description);
return; return;
} }

View File

@@ -65,16 +65,16 @@ DebugView::~DebugView()
void DebugView::modelAttached(Model *model) void DebugView::modelAttached(Model *model)
{ {
log(tr("Model attached"), tr("FileName %1").arg(model->fileUrl().toLocalFile())); log(tr("Model attached"), tr("Filename %1").arg(model->fileUrl().toLocalFile()));
m_debugViewWidget->setDebugViewEnabled(isDebugViewEnabled()); m_debugViewWidget->setDebugViewEnabled(isDebugViewEnabled());
if (isDebugViewEnabled()) if (isDebugViewEnabled())
qDebug() << tr("DebugView is enabled"); qDebug() << tr("Debug view is enabled");
AbstractView::modelAttached(model); AbstractView::modelAttached(model);
} }
void DebugView::modelAboutToBeDetached(Model *model) void DebugView::modelAboutToBeDetached(Model *model)
{ {
log(tr("Model detached"), tr("FileName %1").arg(model->fileUrl().toLocalFile())); log(tr("Model detached"), tr("Filename %1").arg(model->fileUrl().toLocalFile()));
AbstractView::modelAboutToBeDetached(model); AbstractView::modelAboutToBeDetached(model);
} }
@@ -115,7 +115,7 @@ void DebugView::nodeAboutToBeRemoved(const ModelNode &removedNode)
message.setString(&string); message.setString(&string);
message << removedNode << lineBreak; message << removedNode << lineBreak;
foreach (const ModelNode &modelNode, removedNode.allSubModelNodes()) { foreach (const ModelNode &modelNode, removedNode.allSubModelNodes()) {
message << tr("ChildNode:") << modelNode << lineBreak; message << tr("Child node:") << modelNode << lineBreak;
} }
log(tr("Node about to be removed:"), message.readAll()); log(tr("Node about to be removed:"), message.readAll());
@@ -136,10 +136,10 @@ void DebugView::nodeReparented(const ModelNode &node, const NodeAbstractProperty
message << tr("Old parent property:"); message << tr("Old parent property:");
message << lineBreak; message << lineBreak;
message << oldPropertyParent; message << oldPropertyParent;
message << tr("PropertyChangeFlag"); message << tr("Property change flag");
message << lineBreak; message << lineBreak;
message << propertyChange; message << propertyChange;
log(tr("Node reparanted:"), message.readAll()); log(tr("Node reparented:"), message.readAll());
} }
} }
@@ -150,8 +150,8 @@ void DebugView::nodeIdChanged(const ModelNode &node, const QString &newId, const
QString string; QString string;
message.setString(&string); message.setString(&string);
message << node; message << node;
message << tr("New Id:") << ' ' << newId << lineBreak; message << tr("New id:") << ' ' << newId << lineBreak;
message << tr("Old Id:") << ' ' << oldId << lineBreak; message << tr("Old id:") << ' ' << oldId << lineBreak;
log(tr("Node id changed:"), string); log(tr("Node id changed:"), string);
} }
} }
@@ -170,7 +170,7 @@ void DebugView::variantPropertiesChanged(const QList<VariantProperty> &propertyL
foreach (const VariantProperty &property, propertyList) { foreach (const VariantProperty &property, propertyList) {
message << property; message << property;
} }
log(tr("VariantProperties changed:"), string); log(tr("Variant properties changed:"), string);
} }
} }
@@ -184,7 +184,7 @@ void DebugView::bindingPropertiesChanged(const QList<BindingProperty> &propertyL
foreach (const BindingProperty &property, propertyList) { foreach (const BindingProperty &property, propertyList) {
message << property; message << property;
} }
log(tr("BindingProperties changed:"), string); log(tr("Binding properties changed:"), string);
} }
} }
@@ -197,7 +197,7 @@ void DebugView::signalHandlerPropertiesChanged(const QVector<SignalHandlerProper
foreach (const SignalHandlerProperty &property, propertyList) { foreach (const SignalHandlerProperty &property, propertyList) {
message << property; message << property;
} }
log(tr("SignalHandlerProperties changed:"), string); log(tr("Signal handler properties changed:"), string);
} }
} }
@@ -257,7 +257,7 @@ void DebugView::auxiliaryDataChanged(const ModelNode &node, const PropertyName &
message << name; message << name;
message << data.toString(); message << data.toString();
log(tr("Auxiliary Data Changed:"), string); log(tr("Auxiliary data changed:"), string);
} }
} }
@@ -323,7 +323,7 @@ void DebugView::instancesCompleted(const QVector<ModelNode> &completedNodeList)
} }
} }
logInstance(tr("Instance Completed"), string); logInstance(tr("Instance completed"), string);
} }
} }
@@ -339,7 +339,7 @@ void DebugView::instanceInformationsChange(const QMultiHash<ModelNode, Informati
message << informationChangeHash.value(modelNode); message << informationChangeHash.value(modelNode);
} }
logInstance(tr("Instance Completed"), string); logInstance(tr("Instance completed"), string);
} }
} }
@@ -366,7 +366,7 @@ void DebugView::instancesChildrenChanged(const QVector<ModelNode> & nodeList)
} }
} }
logInstance(tr("Instances children changed:"), string); logInstance(tr("Instance's children changed:"), string);
} }
} }
@@ -387,7 +387,7 @@ void DebugView::customNotification(const AbstractView *view, const QString &iden
message << variant.toString(); message << variant.toString();
} }
log(tr("Custom Notification:"), string); log(tr("Custom notification:"), string);
} }
} }
@@ -401,7 +401,7 @@ void DebugView::nodeSourceChanged(const ModelNode &modelNode, const QString &new
message << modelNode; message << modelNode;
message << newNodeSource; message << newNodeSource;
log(tr("Node Source Changed:"), string); log(tr("Node source changed:"), string);
} }
} }
@@ -414,7 +414,7 @@ void DebugView::nodeRemoved(const ModelNode &removedNode, const NodeAbstractProp
message << removedNode; message << removedNode;
log(tr("Node Removed:"), string); log(tr("Node removed:"), string);
} }
} }

View File

@@ -115,13 +115,13 @@ QList<QToolButton *> ConnectionViewWidget::createToolBarWidgets()
buttons << new QToolButton(); buttons << new QToolButton();
buttons.last()->setIcon(QIcon(QStringLiteral(":/connectionview/plus.png"))); buttons.last()->setIcon(QIcon(QStringLiteral(":/connectionview/plus.png")));
buttons.last()->setToolTip(tr("Add binding or connection")); buttons.last()->setToolTip(tr("Add binding or connection."));
connect(buttons.last(), SIGNAL(clicked()), this, SLOT(addButtonClicked())); connect(buttons.last(), SIGNAL(clicked()), this, SLOT(addButtonClicked()));
connect(this, SIGNAL(setEnabledAddButtonChanged(bool)), buttons.last(), SLOT(setEnabled(bool))); connect(this, SIGNAL(setEnabledAddButtonChanged(bool)), buttons.last(), SLOT(setEnabled(bool)));
buttons << new QToolButton(); buttons << new QToolButton();
buttons.last()->setIcon(QIcon(QStringLiteral(":/connectionview/minus.png"))); buttons.last()->setIcon(QIcon(QStringLiteral(":/connectionview/minus.png")));
buttons.last()->setToolTip(tr("Remove selected binding or connection")); buttons.last()->setToolTip(tr("Remove selected binding or connection."));
buttons.last()->setShortcut(QKeySequence(Qt::Key_Delete)); buttons.last()->setShortcut(QKeySequence(Qt::Key_Delete));
connect(buttons.last(), SIGNAL(clicked()), this, SLOT(removeButtonClicked())); connect(buttons.last(), SIGNAL(clicked()), this, SLOT(removeButtonClicked()));
connect(this, SIGNAL(setEnabledRemoveButtonChanged(bool)), buttons.last(), SLOT(setEnabled(bool))); connect(this, SIGNAL(setEnabledRemoveButtonChanged(bool)), buttons.last(), SLOT(setEnabled(bool)));

View File

@@ -70,7 +70,7 @@ namespace QmlDesigner {
class SourceToolAction : public AbstractAction class SourceToolAction : public AbstractAction
{ {
public: public:
SourceToolAction() : AbstractAction(QCoreApplication::translate("SourceToolAction","Change Source Url...")) {} SourceToolAction() : AbstractAction(QCoreApplication::translate("SourceToolAction","Change Source URL...")) {}
QByteArray category() const QByteArray category() const
{ {

View File

@@ -177,7 +177,7 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Path where Qt Creator can find the qmlpuppet (QML emulation layer) executables.</string> <string>Path where Qt Creator can find the QML emulation layer executable (qmlpuppet).</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@@ -120,8 +120,15 @@ void QmlProfilerClientManager::discardPendingData()
void QmlProfilerClientManager::connectClient(quint16 port) void QmlProfilerClientManager::connectClient(quint16 port)
{ {
if (d->connection) if (d->connection) {
delete d->connection; if (port == d->tcpPort) {
tryToConnect();
return;
} else {
delete d->connection;
}
}
d->connection = new QmlDebugConnection; d->connection = new QmlDebugConnection;
enableServices(); enableServices();
connect(d->connection, SIGNAL(stateMessage(QString)), this, SLOT(logState(QString))); connect(d->connection, SIGNAL(stateMessage(QString)), this, SLOT(logState(QString)));

View File

@@ -309,7 +309,7 @@ void ColorSchemeEdit::updateUnderlineControls()
QSignalBlocker comboBoxSignalBlocker(m_ui->underlineComboBox); QSignalBlocker comboBoxSignalBlocker(m_ui->underlineComboBox);
bool isVisble= formatDescription.showControl(FormatDescription::ShowFontControls); bool isVisble= formatDescription.showControl(FormatDescription::ShowUnderlineControl);
m_ui->underlineLabel->setVisible(isVisble); m_ui->underlineLabel->setVisible(isVisble);
m_ui->underlineColorToolButton->setVisible(isVisble); m_ui->underlineColorToolButton->setVisible(isVisble);

View File

@@ -32,6 +32,8 @@
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <aggregation/aggregate.h>
#include <coreplugin/find/basetextfind.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/outputformatter.h> #include <utils/outputformatter.h>
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
@@ -288,8 +290,12 @@ public:
Internal::OutputWindowPlainTextEdit *VcsOutputWindowPrivate::plainTextEdit() Internal::OutputWindowPlainTextEdit *VcsOutputWindowPrivate::plainTextEdit()
{ {
if (!m_plainTextEdit) if (!m_plainTextEdit) {
m_plainTextEdit = new Internal::OutputWindowPlainTextEdit(); m_plainTextEdit = new Internal::OutputWindowPlainTextEdit();
Aggregation::Aggregate *agg = new Aggregation::Aggregate;
agg->add(m_plainTextEdit);
agg->add(new Core::BaseTextFind(m_plainTextEdit));
}
return m_plainTextEdit; return m_plainTextEdit;
} }

View File

@@ -100,12 +100,19 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName)
return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName); return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName);
} }
inline static
bool isSpecialChar(ushort c, const uchar (&iqm)[16])
{
if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
return true;
return false;
}
inline static inline static
bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16]) bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
{ {
for (int x = arg.length() - 1; x >= 0; --x) { for (int x = arg.length() - 1; x >= 0; --x) {
ushort c = arg.unicode()[x].unicode(); if (isSpecialChar(arg.unicode()[x].unicode(), iqm))
if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
return true; return true;
} }
return false; return false;
@@ -120,7 +127,7 @@ QString IoUtils::shellQuoteUnix(const QString &arg)
}; // 0-32 \'"$`<>|;&(){}*?#!~[] }; // 0-32 \'"$`<>|;&(){}*?#!~[]
if (!arg.length()) if (!arg.length())
return QString::fromLatin1("\"\""); return QString::fromLatin1("''");
QString ret(arg); QString ret(arg);
if (hasSpecialChars(ret, iqm)) { if (hasSpecialChars(ret, iqm)) {
@@ -141,23 +148,38 @@ QString IoUtils::shellQuoteWin(const QString &arg)
0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78, 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
}; };
// Shell meta chars that need escaping.
static const uchar ism[] = {
0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50,
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
}; // &()<>^|
if (!arg.length()) if (!arg.length())
return QString::fromLatin1("\"\""); return QString::fromLatin1("\"\"");
QString ret(arg); QString ret(arg);
if (hasSpecialChars(ret, iqm)) { if (hasSpecialChars(ret, iqm)) {
// Quotes are escaped and their preceding backslashes are doubled. // The process-level standard quoting allows escaping quotes with backslashes (note
// It's impossible to escape anything inside a quoted string on cmd // that backslashes don't escape themselves, unless they are followed by a quote).
// level, so the outer quoting must be "suspended". // Consequently, quotes are escaped and their preceding backslashes are doubled.
ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\"")); ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\""));
// The argument must not end with a \ since this would be interpreted // Trailing backslashes must be doubled as well, as they are followed by a quote.
// as escaping the quote -- rather put the \ behind the quote: e.g. ret.replace(QRegExp(QLatin1String("(\\\\+)$")), QLatin1String("\\1\\1"));
// rather use "foo"\ than "foo\" // However, the shell also interprets the command, and no backslash-escaping exists
int i = ret.length(); // there - a quote always toggles the quoting state, but is nonetheless passed down
while (i > 0 && ret.at(i - 1) == QLatin1Char('\\')) // to the called process verbatim. In the unquoted state, the circumflex escapes
--i; // meta chars (including itself and quotes), and is removed from the command.
ret.insert(i, QLatin1Char('"')); bool quoted = true;
for (int i = 0; i < ret.length(); i++) {
QChar c = ret.unicode()[i];
if (c.unicode() == '"')
quoted = !quoted;
else if (!quoted && isSpecialChar(c.unicode(), ism))
ret.insert(i++, QLatin1Char('^'));
}
if (!quoted)
ret.append(QLatin1Char('^'));
ret.append(QLatin1Char('"'));
ret.prepend(QLatin1Char('"')); ret.prepend(QLatin1Char('"'));
} }
return ret; return ret;

View File

@@ -156,6 +156,18 @@ QString &ProString::toQString(QString &tmp) const
return tmp.setRawData(m_string.constData() + m_offset, m_length); return tmp.setRawData(m_string.constData() + m_offset, m_length);
} }
/*!
* \brief ProString::prepareExtend
* \param extraLen number of new characters to be added
* \param thisTarget offset to which current contents should be moved
* \param extraTarget offset at which new characters will be added
* \return pointer to storage location for new characters
*
* Prepares the string for adding new characters.
* If the string is detached and has enough space, it will be changed in place.
* Otherwise, it will be replaced with a new string object, thus detaching.
* In either case, the hash will be reset.
*/
QChar *ProString::prepareExtend(int extraLen, int thisTarget, int extraTarget) QChar *ProString::prepareExtend(int extraLen, int thisTarget, int extraTarget)
{ {
if (m_string.isDetached() && m_length + extraLen <= m_string.capacity()) { if (m_string.isDetached() && m_length + extraLen <= m_string.capacity()) {
@@ -379,6 +391,20 @@ void ProStringList::removeAll(const char *str)
remove(i); remove(i);
} }
void ProStringList::removeEach(const ProStringList &value)
{
foreach (const ProString &str, value)
if (!str.isEmpty())
removeAll(str);
}
void ProStringList::removeEmpty()
{
for (int i = size(); --i >= 0;)
if (at(i).isEmpty())
remove(i);
}
void ProStringList::removeDuplicates() void ProStringList::removeDuplicates()
{ {
int n = size(); int n = size();
@@ -398,6 +424,13 @@ void ProStringList::removeDuplicates()
erase(begin() + j, end()); erase(begin() + j, end());
} }
void ProStringList::insertUnique(const ProStringList &value)
{
foreach (const ProString &str, value)
if (!str.isEmpty() && !contains(str))
append(str);
}
ProStringList::ProStringList(const QStringList &list) ProStringList::ProStringList(const QStringList &list)
{ {
reserve(list.size()); reserve(list.size());
@@ -409,8 +442,8 @@ QStringList ProStringList::toQStringList() const
{ {
QStringList ret; QStringList ret;
ret.reserve(size()); ret.reserve(size());
foreach (const ProString &str, *this) for (int i = 0; i < size(); i++) // foreach causes MSVC2010 ICE
ret << str.toQString(); ret << at(i).toQString();
return ret; return ret;
} }
@@ -445,4 +478,23 @@ ProFile::~ProFile()
{ {
} }
ProString ProFile::getStr(const ushort *&tPtr)
{
uint len = *tPtr++;
ProString ret(items(), tPtr - tokPtr(), len);
ret.setSource(this);
tPtr += len;
return ret;
}
ProKey ProFile::getHashStr(const ushort *&tPtr)
{
uint hash = *tPtr++;
hash |= (uint)*tPtr++ << 16;
uint len = *tPtr++;
ProKey ret(items(), tPtr - tokPtr(), len, hash);
tPtr += len;
return ret;
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -135,6 +135,7 @@ public:
int toInt(bool *ok = 0, int base = 10) const { return toQString().toInt(ok, base); } // XXX optimize int toInt(bool *ok = 0, int base = 10) const { return toQString().toInt(ok, base); } // XXX optimize
short toShort(bool *ok = 0, int base = 10) const { return toQString().toShort(ok, base); } // XXX optimize short toShort(bool *ok = 0, int base = 10) const { return toQString().toShort(ok, base); } // XXX optimize
uint hash() const { return m_hash; }
static uint hash(const QChar *p, int n); static uint hash(const QChar *p, int n);
ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); } ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); }
@@ -236,9 +237,13 @@ public:
QString join(const QString &sep) const; QString join(const QString &sep) const;
QString join(QChar sep) const; QString join(QChar sep) const;
void insertUnique(const ProStringList &value);
void removeAll(const ProString &str); void removeAll(const ProString &str);
void removeAll(const char *str); void removeAll(const char *str);
void removeEach(const ProStringList &value);
void removeAt(int idx) { remove(idx); } void removeAt(int idx) { remove(idx); }
void removeEmpty();
void removeDuplicates(); void removeDuplicates();
bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
@@ -345,6 +350,9 @@ public:
bool isHostBuild() const { return m_hostBuild; } bool isHostBuild() const { return m_hostBuild; }
void setHostBuild(bool host_build) { m_hostBuild = host_build; } void setHostBuild(bool host_build) { m_hostBuild = host_build; }
ProString getStr(const ushort *&tPtr);
ProKey getHashStr(const ushort *&tPtr);
private: private:
ProItemRefCount m_refCount; ProItemRefCount m_refCount;
QString m_proitems; QString m_proitems;

View File

@@ -88,7 +88,7 @@ enum ExpandFunc {
E_UPPER, E_LOWER, E_TITLE, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE, E_UPPER, E_LOWER, E_TITLE, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE,
E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS, E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS,
E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH, E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH,
E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE, E_GETENV
}; };
enum TestFunc { enum TestFunc {
@@ -145,6 +145,7 @@ void QMakeEvaluator::initFunctionStatics()
{ "shell_path", E_SHELL_PATH }, { "shell_path", E_SHELL_PATH },
{ "system_quote", E_SYSTEM_QUOTE }, { "system_quote", E_SYSTEM_QUOTE },
{ "shell_quote", E_SHELL_QUOTE }, { "shell_quote", E_SHELL_QUOTE },
{ "getenv", E_GETENV },
}; };
for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i) for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i)
statics.expands.insert(ProKey(expandInits[i].name), expandInits[i].func); statics.expands.insert(ProKey(expandInits[i].name), expandInits[i].func);
@@ -210,12 +211,12 @@ static QString windowsErrorCode()
NULL); NULL);
QString ret = QString::fromWCharArray(string); QString ret = QString::fromWCharArray(string);
LocalFree((HLOCAL)string); LocalFree((HLOCAL)string);
return ret; return ret.trimmed();
} }
#endif #endif
static QString QString
quoteValue(const ProString &val) QMakeEvaluator::quoteValue(const ProString &val)
{ {
QString ret; QString ret;
ret.reserve(val.size()); ret.reserve(val.size());
@@ -358,7 +359,7 @@ QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::Open
{ {
QString errStr; QString errStr;
if (!m_vfs->writeFile(fn, mode, contents, &errStr)) { if (!m_vfs->writeFile(fn, mode, contents, &errStr)) {
evalError(fL1S("Cannot write %1file %2: %3.") evalError(fL1S("Cannot write %1file %2: %3")
.arg(ctx, QDir::toNativeSeparators(fn), errStr)); .arg(ctx, QDir::toNativeSeparators(fn), errStr));
return ReturnFalse; return ReturnFalse;
} }
@@ -425,8 +426,9 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args) const
void QMakeEvaluator::populateDeps( void QMakeEvaluator::populateDeps(
const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes, const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes,
const ProString &priosfx,
QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees, QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
ProStringList &rootSet) const QMultiMap<int, ProString> &rootSet) const
{ {
foreach (const ProString &item, deps) foreach (const ProString &item, deps)
if (!dependencies.contains(item.toKey())) { if (!dependencies.contains(item.toKey())) {
@@ -435,13 +437,13 @@ void QMakeEvaluator::populateDeps(
foreach (const ProString &suffix, suffixes) foreach (const ProString &suffix, suffixes)
depends += values(ProKey(prefix + item + suffix)); depends += values(ProKey(prefix + item + suffix));
if (depends.isEmpty()) { if (depends.isEmpty()) {
rootSet << item; rootSet.insert(first(ProKey(prefix + item + priosfx)).toInt(), item);
} else { } else {
foreach (const ProString &dep, depends) { foreach (const ProString &dep, depends) {
dset.insert(dep.toKey()); dset.insert(dep.toKey());
dependees[dep.toKey()] << item; dependees[dep.toKey()] << item;
} }
populateDeps(depends, prefix, suffixes, dependencies, dependees, rootSet); populateDeps(depends, prefix, suffixes, priosfx, dependencies, dependees, rootSet);
} }
} }
} }
@@ -962,27 +964,31 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
break; break;
case E_SORT_DEPENDS: case E_SORT_DEPENDS:
case E_RESOLVE_DEPENDS: case E_RESOLVE_DEPENDS:
if (args.count() < 1 || args.count() > 3) { if (args.count() < 1 || args.count() > 4) {
evalError(fL1S("%1(var, [prefix, [suffixes]]) requires one to three arguments.") evalError(fL1S("%1(var, [prefix, [suffixes, [prio-suffix]]]) requires one to four arguments.")
.arg(func.toQString(m_tmp1))); .arg(func.toQString(m_tmp1)));
} else { } else {
QHash<ProKey, QSet<ProKey> > dependencies; QHash<ProKey, QSet<ProKey> > dependencies;
ProValueMap dependees; ProValueMap dependees;
ProStringList rootSet; QMultiMap<int, ProString> rootSet;
ProStringList orgList = values(args.at(0).toKey()); ProStringList orgList = values(args.at(0).toKey());
populateDeps(orgList, (args.count() < 2 ? ProString() : args.at(1)), ProString prefix = args.count() < 2 ? ProString() : args.at(1);
ProString priosfx = args.count() < 4 ? ProString(".priority") : args.at(3);
populateDeps(orgList, prefix,
args.count() < 3 ? ProStringList(ProString(".depends")) args.count() < 3 ? ProStringList(ProString(".depends"))
: split_value_list(args.at(2).toQString(m_tmp2)), : split_value_list(args.at(2).toQString(m_tmp2)),
dependencies, dependees, rootSet); priosfx, dependencies, dependees, rootSet);
for (int i = 0; i < rootSet.size(); ++i) { while (!rootSet.isEmpty()) {
const ProString &item = rootSet.at(i); QMultiMap<int, ProString>::iterator it = rootSet.begin();
const ProString item = *it;
rootSet.erase(it);
if ((func_t == E_RESOLVE_DEPENDS) || orgList.contains(item)) if ((func_t == E_RESOLVE_DEPENDS) || orgList.contains(item))
ret.prepend(item); ret.prepend(item);
foreach (const ProString &dep, dependees[item.toKey()]) { foreach (const ProString &dep, dependees[item.toKey()]) {
QSet<ProKey> &dset = dependencies[dep.toKey()]; QSet<ProKey> &dset = dependencies[dep.toKey()];
dset.remove(rootSet.at(i).toKey()); // *Don't* use 'item' - rootSet may have changed! dset.remove(item.toKey());
if (dset.isEmpty()) if (dset.isEmpty())
rootSet << dep; rootSet.insert(first(ProKey(prefix + dep + priosfx)).toInt(), dep);
} }
} }
} }
@@ -1052,10 +1058,18 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
evalError(fL1S("shell_path(path) requires one argument.")); evalError(fL1S("shell_path(path) requires one argument."));
} else { } else {
QString rstr = args.at(0).toQString(m_tmp1); QString rstr = args.at(0).toQString(m_tmp1);
if (m_dirSep.startsWith(QLatin1Char('\\'))) if (m_dirSep.startsWith(QLatin1Char('\\'))) {
rstr.replace(QLatin1Char('/'), QLatin1Char('\\')); rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
else } else {
rstr.replace(QLatin1Char('\\'), QLatin1Char('/')); rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
#ifdef Q_OS_WIN
// Convert d:/foo/bar to msys-style /d/foo/bar.
if (rstr.length() > 2 && rstr.at(1) == QLatin1Char(':') && rstr.at(2) == QLatin1Char('/')) {
rstr[1] = rstr.at(0);
rstr[0] = QLatin1Char('/');
}
#endif
}
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0))); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
} }
break; break;
@@ -1079,6 +1093,15 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0))); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
} }
break; break;
case E_GETENV:
if (args.count() != 1) {
evalError(fL1S("getenv(arg) requires one argument."));
} else {
const ProString &var = args.at(0);
const ProString &val = ProString(m_option->getEnv(var.toQString(m_tmp1)));
ret << val;
}
break;
default: default:
evalError(fL1S("Function '%1' is not implemented.").arg(func.toQString(m_tmp1))); evalError(fL1S("Function '%1' is not implemented.").arg(func.toQString(m_tmp1)));
break; break;
@@ -1095,7 +1118,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
switch (func_t) { switch (func_t) {
case T_DEFINED: { case T_DEFINED: {
if (args.count() < 1 || args.count() > 2) { if (args.count() < 1 || args.count() > 2) {
evalError(fL1S("defined(function, [\"test\"|\"replace\"])" evalError(fL1S("defined(function, [\"test\"|\"replace\"|\"var\"])"
" requires one or two arguments.")); " requires one or two arguments."));
return ReturnFalse; return ReturnFalse;
} }
@@ -1176,15 +1199,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
VisitReturn ret = ReturnFalse; VisitReturn ret = ReturnFalse;
ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep), ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep),
m_current.pro->fileName(), m_current.line); m_current.pro->fileName(), m_current.line);
if (pro) { if (m_cumulative || pro->isOk()) {
if (m_cumulative || pro->isOk()) { m_locationStack.push(m_current);
m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr());
visitProBlock(pro, pro->tokPtr()); ret = ReturnTrue; // This return value is not too useful, but that's qmake
ret = ReturnTrue; // This return value is not too useful, but that's qmake m_current = m_locationStack.pop();
m_current = m_locationStack.pop();
}
pro->deref();
} }
pro->deref();
return ret; return ret;
} }
case T_IF: { case T_IF: {
@@ -1256,9 +1277,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse; return ReturnFalse;
} }
int cnt = values(map(args.at(0))).count(); int cnt = values(map(args.at(0))).count();
int val = args.at(1).toQString(m_tmp1).toInt();
if (args.count() == 3) { if (args.count() == 3) {
const ProString &comp = args.at(2); const ProString &comp = args.at(2);
const int val = args.at(1).toQString(m_tmp1).toInt();
if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) { if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
return returnBool(cnt > val); return returnBool(cnt > val);
} else if (comp == QLatin1String(">=")) { } else if (comp == QLatin1String(">=")) {
@@ -1269,13 +1290,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return returnBool(cnt <= val); return returnBool(cnt <= val);
} else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual")
|| comp == QLatin1String("=") || comp == QLatin1String("==")) { || comp == QLatin1String("=") || comp == QLatin1String("==")) {
return returnBool(cnt == val); // fallthrough
} else { } else {
evalError(fL1S("Unexpected modifier to count(%2).").arg(comp.toQString(m_tmp1))); evalError(fL1S("Unexpected modifier to count(%2).").arg(comp.toQString(m_tmp1)));
return ReturnFalse; return ReturnFalse;
} }
} }
return returnBool(cnt == args.at(1).toQString(m_tmp1).toInt()); return returnBool(cnt == val);
} }
case T_GREATERTHAN: case T_GREATERTHAN:
case T_LESSTHAN: { case T_LESSTHAN: {
@@ -1562,7 +1583,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
GENERIC_READ, FILE_SHARE_READ, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (rHand == INVALID_HANDLE_VALUE) { if (rHand == INVALID_HANDLE_VALUE) {
evalError(fL1S("Cannot open() reference file %1: %2.").arg(rfn, windowsErrorCode())); evalError(fL1S("Cannot open reference file %1: %2").arg(rfn, windowsErrorCode()));
return ReturnFalse; return ReturnFalse;
} }
FILETIME ft; FILETIME ft;
@@ -1572,7 +1593,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
GENERIC_WRITE, FILE_SHARE_READ, GENERIC_WRITE, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (wHand == INVALID_HANDLE_VALUE) { if (wHand == INVALID_HANDLE_VALUE) {
evalError(fL1S("Cannot open() %1: %2.").arg(tfn, windowsErrorCode())); evalError(fL1S("Cannot open %1: %2").arg(tfn, windowsErrorCode()));
return ReturnFalse; return ReturnFalse;
} }
SetFileTime(wHand, 0, 0, &ft); SetFileTime(wHand, 0, 0, &ft);
@@ -1667,7 +1688,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
if (mode == CacheAdd) if (mode == CacheAdd)
newval += diffval; newval += diffval;
else else
removeEach(&newval, diffval); newval.removeEach(diffval);
} }
if (oldval != newval) { if (oldval != newval) {
if (target != TargetStash || !m_stashfile.isEmpty()) { if (target != TargetStash || !m_stashfile.isEmpty()) {
@@ -1720,14 +1741,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
if (target == TargetSuper) { if (target == TargetSuper) {
if (m_superfile.isEmpty()) { if (m_superfile.isEmpty()) {
m_superfile = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.super")); m_superfile = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.super"));
printf("Info: creating super cache file %s\n", qPrintable(m_superfile)); printf("Info: creating super cache file %s\n", qPrintable(QDir::toNativeSeparators(m_superfile)));
valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile); valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile);
} }
fn = m_superfile; fn = m_superfile;
} else if (target == TargetCache) { } else if (target == TargetCache) {
if (m_cachefile.isEmpty()) { if (m_cachefile.isEmpty()) {
m_cachefile = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.cache")); m_cachefile = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.cache"));
printf("Info: creating cache file %s\n", qPrintable(m_cachefile)); printf("Info: creating cache file %s\n", qPrintable(QDir::toNativeSeparators(m_cachefile)));
valuesRef(ProKey("_QMAKE_CACHE_")) << ProString(m_cachefile); valuesRef(ProKey("_QMAKE_CACHE_")) << ProString(m_cachefile);
// We could update m_{source,build}Root and m_featureRoots here, or even // We could update m_{source,build}Root and m_featureRoots here, or even
// "re-home" our rootEnv, but this doesn't sound too useful - if somebody // "re-home" our rootEnv, but this doesn't sound too useful - if somebody
@@ -1741,7 +1762,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
if (fn.isEmpty()) if (fn.isEmpty())
fn = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.stash")); fn = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.stash"));
if (!m_vfs->exists(fn)) { if (!m_vfs->exists(fn)) {
printf("Info: creating stash file %s\n", qPrintable(fn)); printf("Info: creating stash file %s\n", qPrintable(QDir::toNativeSeparators(fn)));
valuesRef(ProKey("_QMAKE_STASH_")) << ProString(fn); valuesRef(ProKey("_QMAKE_STASH_")) << ProString(fn);
} }
} }

View File

@@ -55,6 +55,9 @@
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
#include <unistd.h> #include <unistd.h>
#include <sys/utsname.h> #include <sys/utsname.h>
# ifdef Q_OS_BSD4
# include <sys/sysctl.h>
# endif
#else #else
#include <windows.h> #include <windows.h>
#endif #endif
@@ -67,6 +70,39 @@ QT_BEGIN_NAMESPACE
#define fL1S(s) QString::fromLatin1(s) #define fL1S(s) QString::fromLatin1(s)
// we can't use QThread in qmake
// this function is a merger of QThread::idealThreadCount from qthread_win.cpp and qthread_unix.cpp
static int idealThreadCount()
{
#ifdef PROEVALUATOR_THREAD_SAFE
return QThread::idealThreadCount();
#elif defined(Q_OS_WIN)
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#else
// there are a couple more definitions in the Unix QThread::idealThreadCount, but
// we don't need them all here
int cores = 1;
# if defined(Q_OS_BSD4)
// FreeBSD, OpenBSD, NetBSD, BSD/OS, OS X
size_t len = sizeof(cores);
int mib[2];
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
perror("sysctl");
}
# elif defined(_SC_NPROCESSORS_ONLN)
// the rest: Linux, Solaris, AIX, Tru64
cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
if (cores == -1)
return 1;
# endif
return cores;
#endif
}
QMakeBaseKey::QMakeBaseKey(const QString &_root, const QString &_stash, bool _hostBuild) QMakeBaseKey::QMakeBaseKey(const QString &_root, const QString &_stash, bool _hostBuild)
: root(_root), stash(_stash), hostBuild(_hostBuild) : root(_root), stash(_stash), hostBuild(_hostBuild)
@@ -149,7 +185,8 @@ void QMakeEvaluator::initStatics()
{ "QMAKE_RPATH", "QMAKE_LFLAGS_RPATH" }, { "QMAKE_RPATH", "QMAKE_LFLAGS_RPATH" },
{ "QMAKE_FRAMEWORKDIR", "QMAKE_FRAMEWORKPATH" }, { "QMAKE_FRAMEWORKDIR", "QMAKE_FRAMEWORKPATH" },
{ "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" }, { "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" },
{ "IN_PWD", "PWD" } { "IN_PWD", "PWD" },
{ "DEPLOYMENT", "INSTALLS" }
}; };
for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i) for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i)
statics.varMap.insert(ProKey(mapInits[i].oldname), ProKey(mapInits[i].newname)); statics.varMap.insert(ProKey(mapInits[i].oldname), ProKey(mapInits[i].newname));
@@ -219,24 +256,6 @@ uint QMakeEvaluator::getBlockLen(const ushort *&tokPtr)
return len; return len;
} }
ProString QMakeEvaluator::getStr(const ushort *&tokPtr)
{
uint len = *tokPtr++;
ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len);
ret.setSource(m_current.pro);
tokPtr += len;
return ret;
}
ProKey QMakeEvaluator::getHashStr(const ushort *&tokPtr)
{
uint hash = getBlockLen(tokPtr);
uint len = *tokPtr++;
ProKey ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, hash);
tokPtr += len;
return ret;
}
void QMakeEvaluator::skipStr(const ushort *&tokPtr) void QMakeEvaluator::skipStr(const ushort *&tokPtr)
{ {
uint len = *tokPtr++; uint len = *tokPtr++;
@@ -275,7 +294,8 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil
switch (unicode) { switch (unicode) {
case '"': case '"':
case '\'': case '\'':
quote = unicode; if (!quote)
quote = unicode;
hadWord = true; hadWord = true;
break; break;
case ' ': case ' ':
@@ -311,34 +331,6 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil
return ret; return ret;
} }
static void zipEmpty(ProStringList *value)
{
for (int i = value->size(); --i >= 0;)
if (value->at(i).isEmpty())
value->remove(i);
}
static void insertUnique(ProStringList *varlist, const ProStringList &value)
{
foreach (const ProString &str, value)
if (!str.isEmpty() && !varlist->contains(str))
varlist->append(str);
}
static void removeAll(ProStringList *varlist, const ProString &value)
{
for (int i = varlist->size(); --i >= 0; )
if (varlist->at(i) == value)
varlist->remove(i);
}
void QMakeEvaluator::removeEach(ProStringList *varlist, const ProStringList &value)
{
foreach (const ProString &str, value)
if (!str.isEmpty())
removeAll(varlist, str);
}
static void replaceInList(ProStringList *varlist, static void replaceInList(ProStringList *varlist,
const QRegExp &regexp, const QString &replace, bool global, QString &tmp) const QRegExp &regexp, const QString &replace, bool global, QString &tmp)
{ {
@@ -418,6 +410,7 @@ void QMakeEvaluator::evaluateExpression(
const ushort *&tokPtr, ProStringList *ret, bool joined) const ushort *&tokPtr, ProStringList *ret, bool joined)
{ {
debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression"); debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression");
ProFile *pro = m_current.pro;
if (joined) if (joined)
*ret << ProString(); *ret << ProString();
bool pending = false; bool pending = false;
@@ -433,35 +426,35 @@ void QMakeEvaluator::evaluateExpression(
m_current.line = *tokPtr++; m_current.line = *tokPtr++;
break; break;
case TokLiteral: { case TokLiteral: {
const ProString &val = getStr(tokPtr); const ProString &val = pro->getStr(tokPtr);
debugMsg(2, "literal %s", dbgStr(val)); debugMsg(2, "literal %s", dbgStr(val));
addStr(val, ret, pending, joined); addStr(val, ret, pending, joined);
break; } break; }
case TokHashLiteral: { case TokHashLiteral: {
const ProKey &val = getHashStr(tokPtr); const ProKey &val = pro->getHashStr(tokPtr);
debugMsg(2, "hashed literal %s", dbgStr(val.toString())); debugMsg(2, "hashed literal %s", dbgStr(val.toString()));
addStr(val, ret, pending, joined); addStr(val, ret, pending, joined);
break; } break; }
case TokVariable: { case TokVariable: {
const ProKey &var = getHashStr(tokPtr); const ProKey &var = pro->getHashStr(tokPtr);
const ProStringList &val = values(map(var)); const ProStringList &val = values(map(var));
debugMsg(2, "variable %s => %s", dbgKey(var), dbgStrList(val)); debugMsg(2, "variable %s => %s", dbgKey(var), dbgStrList(val));
addStrList(val, tok, ret, pending, joined); addStrList(val, tok, ret, pending, joined);
break; } break; }
case TokProperty: { case TokProperty: {
const ProKey &var = getHashStr(tokPtr); const ProKey &var = pro->getHashStr(tokPtr);
const ProString &val = propertyValue(var); const ProString &val = propertyValue(var);
debugMsg(2, "property %s => %s", dbgKey(var), dbgStr(val)); debugMsg(2, "property %s => %s", dbgKey(var), dbgStr(val));
addStr(val, ret, pending, joined); addStr(val, ret, pending, joined);
break; } break; }
case TokEnvVar: { case TokEnvVar: {
const ProString &var = getStr(tokPtr); const ProString &var = pro->getStr(tokPtr);
const ProString &val = ProString(m_option->getEnv(var.toQString())); const ProString &val = ProString(m_option->getEnv(var.toQString()));
debugMsg(2, "env var %s => %s", dbgStr(var), dbgStr(val)); debugMsg(2, "env var %s => %s", dbgStr(var), dbgStr(val));
addStr(val, ret, pending, joined); addStr(val, ret, pending, joined);
break; } break; }
case TokFuncName: { case TokFuncName: {
const ProKey &func = getHashStr(tokPtr); const ProKey &func = pro->getHashStr(tokPtr);
debugMsg(2, "function %s", dbgKey(func)); debugMsg(2, "function %s", dbgKey(func));
addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined); addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
break; } break; }
@@ -526,6 +519,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
{ {
traceMsg("entering block"); traceMsg("entering block");
ProStringList curr; ProStringList curr;
ProFile *pro = m_current.pro;
bool okey = true, or_op = false, invert = false; bool okey = true, or_op = false, invert = false;
uint blockLen; uint blockLen;
while (ushort tok = *tokPtr++) { while (ushort tok = *tokPtr++) {
@@ -579,7 +573,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
break; break;
case TokForLoop: case TokForLoop:
if (m_cumulative || okey != or_op) { if (m_cumulative || okey != or_op) {
const ProKey &variable = getHashStr(tokPtr); const ProKey &variable = pro->getHashStr(tokPtr);
uint exprLen = getBlockLen(tokPtr); uint exprLen = getBlockLen(tokPtr);
const ushort *exprPtr = tokPtr; const ushort *exprPtr = tokPtr;
tokPtr += exprLen; tokPtr += exprLen;
@@ -599,7 +593,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
case TokTestDef: case TokTestDef:
case TokReplaceDef: case TokReplaceDef:
if (m_cumulative || okey != or_op) { if (m_cumulative || okey != or_op) {
const ProKey &name = getHashStr(tokPtr); const ProKey &name = pro->getHashStr(tokPtr);
blockLen = getBlockLen(tokPtr); blockLen = getBlockLen(tokPtr);
visitProFunctionDef(tok, name, tokPtr); visitProFunctionDef(tok, name, tokPtr);
traceMsg("defined %s function %s", traceMsg("defined %s function %s",
@@ -790,8 +784,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
forever { forever {
if (infinite) { if (infinite) {
if (!variable.isEmpty()) if (!variable.isEmpty())
m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index++))); m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index)));
if (index > 1000) { if (++index > 1000) {
evalError(fL1S("Ran into infinite loop (> 1000 iterations).")); evalError(fL1S("Ran into infinite loop (> 1000 iterations)."));
break; break;
} }
@@ -882,24 +876,24 @@ void QMakeEvaluator::visitProVariable(
switch (tok) { switch (tok) {
default: // whatever - cannot happen default: // whatever - cannot happen
case TokAssign: // = case TokAssign: // =
zipEmpty(&varVal); varVal.removeEmpty();
// FIXME: add check+warning about accidental value removal. // FIXME: add check+warning about accidental value removal.
// This may be a bit too noisy, though. // This may be a bit too noisy, though.
m_valuemapStack.top()[varName] = varVal; m_valuemapStack.top()[varName] = varVal;
debugMsg(2, "assigning"); debugMsg(2, "assigning");
break; break;
case TokAppendUnique: // *= case TokAppendUnique: // *=
insertUnique(&valuesRef(varName), varVal); valuesRef(varName).insertUnique(varVal);
debugMsg(2, "appending unique"); debugMsg(2, "appending unique");
break; break;
case TokAppend: // += case TokAppend: // +=
zipEmpty(&varVal); varVal.removeEmpty();
valuesRef(varName) += varVal; valuesRef(varName) += varVal;
debugMsg(2, "appending"); debugMsg(2, "appending");
break; break;
case TokRemove: // -= case TokRemove: // -=
if (!m_cumulative) { if (!m_cumulative) {
removeEach(&valuesRef(varName), varVal); valuesRef(varName).removeEach(varVal);
} else { } else {
// We are stingy with our values. // We are stingy with our values.
} }
@@ -949,6 +943,49 @@ void QMakeEvaluator::setTemplate()
} }
} }
#if defined(Q_CC_MSVC)
static ProString msvcBinDirToQMakeArch(QString subdir)
{
int idx = subdir.indexOf(QLatin1Char('\\'));
if (idx == -1)
return ProString("x86");
subdir.remove(0, idx + 1);
idx = subdir.indexOf(QLatin1Char('_'));
if (idx >= 0)
subdir.remove(0, idx + 1);
subdir = subdir.toLower();
if (subdir == QStringLiteral("amd64"))
return ProString("x86_64");
return ProString(subdir);
}
static ProString defaultMsvcArchitecture()
{
#if defined(Q_OS_WIN64)
return ProString("x86_64");
#else
return ProString("x86");
#endif
}
static ProString msvcArchitecture(const QString &vcInstallDir, const QString &pathVar)
{
if (vcInstallDir.isEmpty())
return defaultMsvcArchitecture();
QString vcBinDir = vcInstallDir;
if (vcBinDir.endsWith(QLatin1Char('\\')))
vcBinDir.chop(1);
foreach (const QString &dir, pathVar.split(QLatin1Char(';'))) {
if (!dir.startsWith(vcBinDir, Qt::CaseInsensitive))
continue;
const ProString arch = msvcBinDirToQMakeArch(dir.mid(vcBinDir.length() + 1));
if (!arch.isEmpty())
return arch;
}
return defaultMsvcArchitecture();
}
#endif // defined(Q_CC_MSVC)
void QMakeEvaluator::loadDefaults() void QMakeEvaluator::loadDefaults()
{ {
ProValueMap &vars = m_valuemapStack.top(); ProValueMap &vars = m_valuemapStack.top();
@@ -960,6 +997,7 @@ void QMakeEvaluator::loadDefaults()
vars[ProKey("QMAKE_QMAKE")] << ProString(m_option->qmake_abslocation); vars[ProKey("QMAKE_QMAKE")] << ProString(m_option->qmake_abslocation);
if (!m_option->qmake_args.isEmpty()) if (!m_option->qmake_args.isEmpty())
vars[ProKey("QMAKE_ARGS")] = ProStringList(m_option->qmake_args); vars[ProKey("QMAKE_ARGS")] = ProStringList(m_option->qmake_args);
vars[ProKey("QMAKE_HOST.cpu_count")] = ProString(QString::number(idealThreadCount()));
#if defined(Q_OS_WIN32) #if defined(Q_OS_WIN32)
vars[ProKey("QMAKE_HOST.os")] << ProString("Windows"); vars[ProKey("QMAKE_HOST.os")] << ProString("Windows");
@@ -1009,21 +1047,9 @@ void QMakeEvaluator::loadDefaults()
vars[ProKey("QMAKE_HOST.arch")] << archStr; vars[ProKey("QMAKE_HOST.arch")] << archStr;
# if defined(Q_CC_MSVC) // ### bogus condition, but nobody x-builds for msvc with a different qmake # if defined(Q_CC_MSVC) // ### bogus condition, but nobody x-builds for msvc with a different qmake
QLatin1Char backslash('\\'); vars[ProKey("QMAKE_TARGET.arch")] = msvcArchitecture(
QString paths = m_option->getEnv(QLatin1String("PATH")); m_option->getEnv(QLatin1String("VCINSTALLDIR")),
QString vcBin64 = m_option->getEnv(QLatin1String("VCINSTALLDIR")); m_option->getEnv(QLatin1String("PATH")));
if (!vcBin64.endsWith(backslash))
vcBin64.append(backslash);
vcBin64.append(QLatin1String("bin\\amd64"));
QString vcBinX86_64 = m_option->getEnv(QLatin1String("VCINSTALLDIR"));
if (!vcBinX86_64.endsWith(backslash))
vcBinX86_64.append(backslash);
vcBinX86_64.append(QLatin1String("bin\\x86_amd64"));
if (paths.contains(vcBin64, Qt::CaseInsensitive)
|| paths.contains(vcBinX86_64, Qt::CaseInsensitive))
vars[ProKey("QMAKE_TARGET.arch")] << ProString("x86_64");
else
vars[ProKey("QMAKE_TARGET.arch")] << ProString("x86");
# endif # endif
#elif defined(Q_OS_UNIX) #elif defined(Q_OS_UNIX)
struct utsname name; struct utsname name;
@@ -1247,14 +1273,13 @@ void QMakeEvaluator::setupProject()
void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where)
{ {
if (!cmds.isEmpty()) { if (!cmds.isEmpty()) {
if (ProFile *pro = m_parser->parsedProBlock(cmds, where, -1)) { ProFile *pro = m_parser->parsedProBlock(cmds, where, -1);
if (pro->isOk()) { if (pro->isOk()) {
m_locationStack.push(m_current); m_locationStack.push(m_current);
visitProBlock(pro, pro->tokPtr()); visitProBlock(pro, pro->tokPtr());
m_current = m_locationStack.pop(); m_current = m_locationStack.pop();
}
pro->deref();
} }
pro->deref();
} }
} }
@@ -1734,14 +1759,12 @@ bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &whe
{ {
bool ret = false; bool ret = false;
ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar); ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar);
if (pro) { if (pro->isOk()) {
if (pro->isOk()) { m_locationStack.push(m_current);
m_locationStack.push(m_current); ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue;
ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue; m_current = m_locationStack.pop();
m_current = m_locationStack.pop();
}
pro->deref();
} }
pro->deref();
return ret; return ret;
} }

View File

@@ -38,8 +38,10 @@
#include "qmakeparser.h" #include "qmakeparser.h"
#include "ioutils.h" #include "ioutils.h"
#include <qiodevice.h>
#include <qlist.h> #include <qlist.h>
#include <qlinkedlist.h> #include <qlinkedlist.h>
#include <qmap.h>
#include <qset.h> #include <qset.h>
#include <qstack.h> #include <qstack.h>
#include <qstring.h> #include <qstring.h>
@@ -145,8 +147,6 @@ public:
{ return b ? ReturnTrue : ReturnFalse; } { return b ? ReturnTrue : ReturnFalse; }
static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr); static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr);
ProString getStr(const ushort *&tokPtr);
ProKey getHashStr(const ushort *&tokPtr);
void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined); void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
static ALWAYS_INLINE void skipStr(const ushort *&tokPtr); static ALWAYS_INLINE void skipStr(const ushort *&tokPtr);
static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr); static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr);
@@ -227,8 +227,9 @@ public:
void populateDeps( void populateDeps(
const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes, const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes,
QHash<ProKey, QSet<ProKey> > &dependencies, const ProString &priosfx,
ProValueMap &dependees, ProStringList &rootSet) const; QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
QMultiMap<int, ProString> &rootSet) const;
VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
const QString &contents); const QString &contents);
@@ -237,8 +238,6 @@ public:
#endif #endif
QByteArray getCommandOutput(const QString &args) const; QByteArray getCommandOutput(const QString &args) const;
static void removeEach(ProStringList *varlist, const ProStringList &value);
QMakeEvaluator *m_caller; QMakeEvaluator *m_caller;
#ifdef PROEVALUATOR_CUMULATIVE #ifdef PROEVALUATOR_CUMULATIVE
bool m_cumulative; bool m_cumulative;
@@ -248,6 +247,8 @@ public:
enum { m_skipLevel = 0 }; enum { m_skipLevel = 0 };
#endif #endif
static QString quoteValue(const ProString &val);
#ifdef PROEVALUATOR_DEBUG #ifdef PROEVALUATOR_DEBUG
void debugMsgInternal(int level, const char *fmt, ...) const; void debugMsgInternal(int level, const char *fmt, ...) const;
void traceMsgInternal(const char *fmt, ...) const; void traceMsgInternal(const char *fmt, ...) const;
@@ -306,6 +307,7 @@ public:
QMakeHandler *m_handler; QMakeHandler *m_handler;
QMakeVfs *m_vfs; QMakeVfs *m_vfs;
}; };
Q_DECLARE_TYPEINFO(QMakeEvaluator::Location, Q_PRIMITIVE_TYPE);
Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags)

View File

@@ -132,6 +132,7 @@ public:
bool initProperties(); bool initProperties();
# else # else
void setProperties(const QHash<QString, QString> &props); void setProperties(const QHash<QString, QString> &props);
void setProperties(const QHash<ProKey, ProString> &props) { properties = props; }
# endif # endif
ProString propertyValue(const ProKey &name) const { return properties.value(name); } ProString propertyValue(const ProKey &name) const { return properties.value(name); }
#endif #endif

View File

@@ -229,10 +229,7 @@ ProFile *QMakeParser::parsedProBlock(
const QString &contents, const QString &name, int line, SubGrammar grammar) const QString &contents, const QString &name, int line, SubGrammar grammar)
{ {
ProFile *pro = new ProFile(name); ProFile *pro = new ProFile(name);
if (!read(pro, contents, line, grammar)) { read(pro, contents, line, grammar);
delete pro;
pro = 0;
}
return pro; return pro;
} }
@@ -252,7 +249,8 @@ bool QMakeParser::read(ProFile *pro, ParseFlags flags)
fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr)); fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr));
return false; return false;
} }
return read(pro, content, 1, FullGrammar); read(pro, content, 1, FullGrammar);
return true;
} }
void QMakeParser::putTok(ushort *&tokPtr, ushort tok) void QMakeParser::putTok(ushort *&tokPtr, ushort tok)
@@ -292,7 +290,7 @@ void QMakeParser::finalizeHashStr(ushort *buf, uint len)
buf[-2] = (ushort)(hash >> 16); buf[-2] = (ushort)(hash >> 16);
} }
bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar) void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar)
{ {
m_proFile = pro; m_proFile = pro;
m_lineNo = line; m_lineNo = line;
@@ -342,7 +340,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
m_canElse = false; m_canElse = false;
freshLine: freshLine:
m_state = StNew; m_state = StNew;
m_invert = false; m_invert = 0;
m_operator = NoOperator; m_operator = NoOperator;
m_markLine = m_lineNo; m_markLine = m_lineNo;
m_inError = false; m_inError = false;
@@ -599,7 +597,6 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
parseError(fL1S("Missing %1 terminator [found %2]") parseError(fL1S("Missing %1 terminator [found %2]")
.arg(QChar(term)) .arg(QChar(term))
.arg(c ? QString(c) : QString::fromLatin1("end-of-line"))); .arg(c ? QString(c) : QString::fromLatin1("end-of-line")));
pro->setOk(false);
m_inError = true; m_inError = true;
// Just parse on, as if there was a terminator ... // Just parse on, as if there was a terminator ...
} else { } else {
@@ -626,7 +623,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
quote = 0; quote = 0;
goto nextChr; goto nextChr;
} else if (c == '!' && ptr == xprPtr && context == CtxTest) { } else if (c == '!' && ptr == xprPtr && context == CtxTest) {
m_invert ^= true; m_invert++;
goto nextChr; goto nextChr;
} }
} else if (c == '\'' || c == '"') { } else if (c == '\'' || c == '"') {
@@ -683,20 +680,20 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
parseError(fL1S("Extra characters after test expression.")); parseError(fL1S("Extra characters after test expression."));
else else
parseError(fL1S("Opening parenthesis without prior test name.")); parseError(fL1S("Opening parenthesis without prior test name."));
pro->setOk(false);
ptr = buf; // Put empty function name ptr = buf; // Put empty function name
} }
*ptr++ = TokTestCall; *ptr++ = TokTestCall;
term = ':'; term = ':';
goto funcCall; goto funcCall;
} else if (c == '!' && ptr == xprPtr) { } else if (c == '!' && ptr == xprPtr) {
m_invert ^= true; m_invert++;
goto nextChr; goto nextChr;
} else if (c == ':') { } else if (c == ':') {
FLUSH_LHS_LITERAL(); FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount); finalizeCond(tokPtr, buf, ptr, wordCount);
warnOperator("in front of AND operator");
if (m_state == StNew) if (m_state == StNew)
parseError(fL1S("And operator without prior condition.")); parseError(fL1S("AND operator without prior condition."));
else else
m_operator = AndOperator; m_operator = AndOperator;
nextItem: nextItem:
@@ -705,26 +702,33 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
} else if (c == '|') { } else if (c == '|') {
FLUSH_LHS_LITERAL(); FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount); finalizeCond(tokPtr, buf, ptr, wordCount);
warnOperator("in front of OR operator");
if (m_state != StCond) if (m_state != StCond)
parseError(fL1S("Or operator without prior condition.")); parseError(fL1S("OR operator without prior condition."));
else else
m_operator = OrOperator; m_operator = OrOperator;
goto nextItem; goto nextItem;
} else if (c == '{') { } else if (c == '{') {
FLUSH_LHS_LITERAL(); FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount); finalizeCond(tokPtr, buf, ptr, wordCount);
flushCond(tokPtr); if (m_operator == AndOperator) {
++m_blockstack.top().braceLevel; languageWarning(fL1S("Excess colon in front of opening brace."));
if (grammar == TestGrammar) { m_operator = NoOperator;
parseError(fL1S("Opening scope not permitted in this context."));
pro->setOk(false);
} }
failOperator("in front of opening brace");
flushCond(tokPtr);
m_state = StNew; // Reset possible StCtrl, so colons get rejected.
++m_blockstack.top().braceLevel;
if (grammar == TestGrammar)
parseError(fL1S("Opening scope not permitted in this context."));
goto nextItem; goto nextItem;
} else if (c == '}') { } else if (c == '}') {
FLUSH_LHS_LITERAL(); FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount); finalizeCond(tokPtr, buf, ptr, wordCount);
flushScopes(tokPtr); m_state = StNew; // De-facto newline
closeScope: closeScope:
flushScopes(tokPtr);
failOperator("in front of closing brace");
if (!m_blockstack.top().braceLevel) { if (!m_blockstack.top().braceLevel) {
parseError(fL1S("Excess closing brace.")); parseError(fL1S("Excess closing brace."));
} else if (!--m_blockstack.top().braceLevel } else if (!--m_blockstack.top().braceLevel
@@ -756,13 +760,12 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
doOp: doOp:
FLUSH_LHS_LITERAL(); FLUSH_LHS_LITERAL();
flushCond(tokPtr); flushCond(tokPtr);
acceptColon("in front of assignment");
putLineMarker(tokPtr); putLineMarker(tokPtr);
if (grammar == TestGrammar) { if (grammar == TestGrammar) {
parseError(fL1S("Assignment not permitted in this context.")); parseError(fL1S("Assignment not permitted in this context."));
pro->setOk(false);
} else if (wordCount != 1) { } else if (wordCount != 1) {
parseError(fL1S("Assignment needs exactly one word on the left hand side.")); parseError(fL1S("Assignment needs exactly one word on the left hand side."));
pro->setOk(false);
// Put empty variable name. // Put empty variable name.
} else { } else {
putBlock(tokPtr, buf, ptr - buf); putBlock(tokPtr, buf, ptr - buf);
@@ -831,7 +834,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
} else if (context == CtxPureValue) { } else if (context == CtxPureValue) {
putTok(tokPtr, TokValueTerminator); putTok(tokPtr, TokValueTerminator);
} else { } else {
bogusTest(tokPtr); bogusTest(tokPtr, QString());
} }
} else if (context == CtxValue) { } else if (context == CtxValue) {
FLUSH_VALUE_LIST(); FLUSH_VALUE_LIST();
@@ -842,6 +845,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
putTok(tokPtr, TokValueTerminator); putTok(tokPtr, TokValueTerminator);
} else { } else {
finalizeCond(tokPtr, buf, ptr, wordCount); finalizeCond(tokPtr, buf, ptr, wordCount);
warnOperator("at end of line");
} }
if (!cur) if (!cur)
break; break;
@@ -857,15 +861,12 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
} }
flushScopes(tokPtr); flushScopes(tokPtr);
if (m_blockstack.size() > 1) { if (m_blockstack.size() > 1 || m_blockstack.top().braceLevel)
parseError(fL1S("Missing closing brace(s).")); parseError(fL1S("Missing closing brace(s)."));
pro->setOk(false);
}
while (m_blockstack.size()) while (m_blockstack.size())
leaveScope(tokPtr); leaveScope(tokPtr);
tokBuff.resize(tokPtr - (ushort *)tokBuff.constData()); // Reserved capacity stays tokBuff.resize(tokPtr - (ushort *)tokBuff.constData()); // Reserved capacity stays
*pro->itemsRef() = tokBuff; *pro->itemsRef() = tokBuff;
return true;
#undef FLUSH_VALUE_LIST #undef FLUSH_VALUE_LIST
#undef FLUSH_LITERAL #undef FLUSH_LITERAL
@@ -938,39 +939,90 @@ void QMakeParser::flushCond(ushort *&tokPtr)
} }
} }
void QMakeParser::warnOperator(const char *msg)
{
if (m_invert) {
languageWarning(fL1S("Stray NOT operator %1.").arg(fL1S(msg)));
m_invert = 0;
}
if (m_operator == AndOperator) {
languageWarning(fL1S("Stray AND operator %1.").arg(fL1S(msg)));
m_operator = NoOperator;
} else if (m_operator == OrOperator) {
languageWarning(fL1S("Stray OR operator %1.").arg(fL1S(msg)));
m_operator = NoOperator;
}
}
bool QMakeParser::failOperator(const char *msg)
{
bool fail = false;
if (m_invert) {
parseError(fL1S("Unexpected NOT operator %1.").arg(fL1S(msg)));
m_invert = 0;
fail = true;
}
if (m_operator == AndOperator) {
parseError(fL1S("Unexpected AND operator %1.").arg(fL1S(msg)));
m_operator = NoOperator;
fail = true;
} else if (m_operator == OrOperator) {
parseError(fL1S("Unexpected OR operator %1.").arg(fL1S(msg)));
m_operator = NoOperator;
fail = true;
}
return fail;
}
bool QMakeParser::acceptColon(const char *msg)
{
if (m_operator == AndOperator)
m_operator = NoOperator;
return !failOperator(msg);
}
void QMakeParser::putOperator(ushort *&tokPtr)
{
if (m_operator== AndOperator) {
// A colon must be used after else and for() if no brace is used,
// but in this case it is obviously not a binary operator.
if (m_state == StCond)
putTok(tokPtr, TokAnd);
m_operator = NoOperator;
} else if (m_operator == OrOperator) {
putTok(tokPtr, TokOr);
m_operator = NoOperator;
}
}
void QMakeParser::finalizeTest(ushort *&tokPtr) void QMakeParser::finalizeTest(ushort *&tokPtr)
{ {
flushScopes(tokPtr); flushScopes(tokPtr);
putLineMarker(tokPtr); putLineMarker(tokPtr);
if (m_operator != NoOperator) { putOperator(tokPtr);
putTok(tokPtr, (m_operator == AndOperator) ? TokAnd : TokOr); if (m_invert & 1)
m_operator = NoOperator;
}
if (m_invert) {
putTok(tokPtr, TokNot); putTok(tokPtr, TokNot);
m_invert = false; m_invert = 0;
}
m_state = StCond; m_state = StCond;
m_canElse = true; m_canElse = true;
} }
void QMakeParser::bogusTest(ushort *&tokPtr) void QMakeParser::bogusTest(ushort *&tokPtr, const QString &msg)
{ {
if (!msg.isEmpty())
parseError(msg);
flushScopes(tokPtr); flushScopes(tokPtr);
m_operator = NoOperator; m_operator = NoOperator;
m_invert = false; m_invert = 0;
m_state = StCond; m_state = StCond;
m_canElse = true; m_canElse = true;
m_proFile->setOk(false);
} }
void QMakeParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount) void QMakeParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount)
{ {
if (wordCount != 1) { if (wordCount != 1) {
if (wordCount) { if (wordCount)
parseError(fL1S("Extra characters after test expression.")); bogusTest(tokPtr, fL1S("Extra characters after test expression."));
bogusTest(tokPtr);
}
return; return;
} }
@@ -981,10 +1033,8 @@ void QMakeParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wor
if (uce == ptr) { if (uce == ptr) {
m_tmp.setRawData((QChar *)uc + 4, nlen); m_tmp.setRawData((QChar *)uc + 4, nlen);
if (!m_tmp.compare(statics.strelse, Qt::CaseInsensitive)) { if (!m_tmp.compare(statics.strelse, Qt::CaseInsensitive)) {
if (m_invert || m_operator != NoOperator) { if (failOperator("in front of else"))
parseError(fL1S("Unexpected operator in front of else."));
return; return;
}
BlockScope &top = m_blockstack.top(); BlockScope &top = m_blockstack.top();
if (m_canElse && (!top.special || top.braceLevel)) { if (m_canElse && (!top.special || top.braceLevel)) {
// A list of tests (the last one likely with side effects), // A list of tests (the last one likely with side effects),
@@ -1029,18 +1079,18 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
const QString *defName; const QString *defName;
ushort defType; ushort defType;
if (m_tmp == statics.strfor) { if (m_tmp == statics.strfor) {
if (m_invert || m_operator == OrOperator) { if (!acceptColon("in front of for()")) {
// '|' could actually work reasonably, but qmake does nonsense here. bogusTest(tokPtr, QString());
parseError(fL1S("Unexpected operator in front of for()."));
bogusTest(tokPtr);
return; return;
} }
flushCond(tokPtr); flushCond(tokPtr);
putLineMarker(tokPtr); putLineMarker(tokPtr);
--ptr;
Q_ASSERT(*ptr == TokFuncTerminator);
if (*uce == (TokLiteral|TokNewStr)) { if (*uce == (TokLiteral|TokNewStr)) {
nlen = uce[1]; nlen = uce[1];
uc = uce + 2 + nlen; uc = uce + 2 + nlen;
if (*uc == TokFuncTerminator) { if (uc == ptr) {
// for(literal) (only "ever" would be legal if qmake was sane) // for(literal) (only "ever" would be legal if qmake was sane)
putTok(tokPtr, TokForLoop); putTok(tokPtr, TokForLoop);
putHashStr(tokPtr, (ushort *)0, (uint)0); putHashStr(tokPtr, (ushort *)0, (uint)0);
@@ -1081,8 +1131,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
defType = TokTestDef; defType = TokTestDef;
deffunc: deffunc:
if (m_invert) { if (m_invert) {
parseError(fL1S("Unexpected operator in front of function definition.")); bogusTest(tokPtr, fL1S("Unexpected NOT operator in front of function definition."));
bogusTest(tokPtr);
return; return;
} }
flushScopes(tokPtr); flushScopes(tokPtr);
@@ -1090,10 +1139,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
if (*uce == (TokLiteral|TokNewStr)) { if (*uce == (TokLiteral|TokNewStr)) {
uint nlen = uce[1]; uint nlen = uce[1];
if (uce[nlen + 2] == TokFuncTerminator) { if (uce[nlen + 2] == TokFuncTerminator) {
if (m_operator != NoOperator) { putOperator(tokPtr);
putTok(tokPtr, (m_operator == AndOperator) ? TokAnd : TokOr);
m_operator = NoOperator;
}
putTok(tokPtr, defType); putTok(tokPtr, defType);
putHashStr(tokPtr, uce + 2, nlen); putHashStr(tokPtr, uce + 2, nlen);
enterScope(tokPtr, true, StCtrl); enterScope(tokPtr, true, StCtrl);
@@ -1106,14 +1152,12 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
} else if (m_tmp == statics.strreturn) { } else if (m_tmp == statics.strreturn) {
if (m_blockstack.top().nest & NestFunction) { if (m_blockstack.top().nest & NestFunction) {
if (argc > 1) { if (argc > 1) {
parseError(fL1S("return() requires zero or one argument.")); bogusTest(tokPtr, fL1S("return() requires zero or one argument."));
bogusTest(tokPtr);
return; return;
} }
} else { } else {
if (*uce != TokFuncTerminator) { if (*uce != TokFuncTerminator) {
parseError(fL1S("Top-level return() requires zero arguments.")); bogusTest(tokPtr, fL1S("Top-level return() requires zero arguments."));
bogusTest(tokPtr);
return; return;
} }
} }
@@ -1126,19 +1170,16 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
defType = TokBreak; defType = TokBreak;
ctrlstm: ctrlstm:
if (*uce != TokFuncTerminator) { if (*uce != TokFuncTerminator) {
parseError(fL1S("%1() requires zero arguments.").arg(m_tmp)); bogusTest(tokPtr, fL1S("%1() requires zero arguments.").arg(m_tmp));
bogusTest(tokPtr);
return; return;
} }
if (!(m_blockstack.top().nest & NestLoop)) { if (!(m_blockstack.top().nest & NestLoop)) {
parseError(fL1S("Unexpected %1().").arg(m_tmp)); bogusTest(tokPtr, fL1S("Unexpected %1().").arg(m_tmp));
bogusTest(tokPtr);
return; return;
} }
ctrlstm2: ctrlstm2:
if (m_invert) { if (m_invert) {
parseError(fL1S("Unexpected NOT operator in front of %1().").arg(m_tmp)); bogusTest(tokPtr, fL1S("Unexpected NOT operator in front of %1().").arg(m_tmp));
bogusTest(tokPtr);
return; return;
} }
finalizeTest(tokPtr); finalizeTest(tokPtr);
@@ -1148,8 +1189,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
} else if (m_tmp == statics.stroption) { } else if (m_tmp == statics.stroption) {
if (m_state != StNew || m_blockstack.top().braceLevel || m_blockstack.size() > 1 if (m_state != StNew || m_blockstack.top().braceLevel || m_blockstack.size() > 1
|| m_invert || m_operator != NoOperator) { || m_invert || m_operator != NoOperator) {
parseError(fL1S("option() must appear outside any control structures.")); bogusTest(tokPtr, fL1S("option() must appear outside any control structures."));
bogusTest(tokPtr);
return; return;
} }
if (*uce == (TokLiteral|TokNewStr)) { if (*uce == (TokLiteral|TokNewStr)) {
@@ -1230,4 +1270,258 @@ void QMakeParser::message(int type, const QString &msg) const
m_handler->message(type, msg, m_proFile->fileName(), m_lineNo); m_handler->message(type, msg, m_proFile->fileName(), m_lineNo);
} }
#ifdef PROPARSER_DEBUG
#define BOUNDS_CHECK(need) \
do { \
int have = limit - offset; \
if (have < (int)need) { \
*outStr += fL1S("<out of bounds (need %1, got %2)>").arg(need).arg(have); \
return false; \
} \
} while (0)
static bool getRawUshort(const ushort *tokens, int limit, int &offset, ushort *outVal, QString *outStr)
{
BOUNDS_CHECK(1);
uint val = tokens[offset++];
*outVal = val;
return true;
}
static bool getUshort(const ushort *tokens, int limit, int &offset, ushort *outVal, QString *outStr)
{
*outStr += fL1S(" << H(");
if (!getRawUshort(tokens, limit, offset, outVal, outStr))
return false;
*outStr += QString::number(*outVal) + QLatin1Char(')');
return true;
}
static bool getRawUint(const ushort *tokens, int limit, int &offset, uint *outVal, QString *outStr)
{
BOUNDS_CHECK(2);
uint val = tokens[offset++];
val |= (uint)tokens[offset++] << 16;
*outVal = val;
return true;
}
static bool getUint(const ushort *tokens, int limit, int &offset, uint *outVal, QString *outStr)
{
*outStr += fL1S(" << I(");
if (!getRawUint(tokens, limit, offset, outVal, outStr))
return false;
*outStr += QString::number(*outVal) + QLatin1Char(')');
return true;
}
static bool getRawStr(const ushort *tokens, int limit, int &offset, int strLen, QString *outStr)
{
BOUNDS_CHECK(strLen);
*outStr += fL1S("L\"");
bool attn = false;
for (int i = 0; i < strLen; i++) {
ushort val = tokens[offset++];
switch (val) {
case '"': *outStr += fL1S("\\\""); break;
case '\n': *outStr += fL1S("\\n"); break;
case '\r': *outStr += fL1S("\\r"); break;
case '\t': *outStr += fL1S("\\t"); break;
case '\\': *outStr += fL1S("\\\\"); break;
default:
if (val < 32 || val > 126) {
*outStr += (val > 255 ? fL1S("\\u") : fL1S("\\x")) + QString::number(val, 16);
attn = true;
continue;
}
if (attn && isxdigit(val))
*outStr += fL1S("\"\"");
*outStr += QChar(val);
break;
}
attn = false;
}
*outStr += QLatin1Char('"');
return true;
}
static bool getStr(const ushort *tokens, int limit, int &offset, QString *outStr)
{
*outStr += fL1S(" << S(");
ushort len;
if (!getRawUshort(tokens, limit, offset, &len, outStr))
return false;
if (!getRawStr(tokens, limit, offset, len, outStr))
return false;
*outStr += QLatin1Char(')');
return true;
}
static bool getHashStr(const ushort *tokens, int limit, int &offset, QString *outStr)
{
*outStr += fL1S(" << HS(");
uint hash;
if (!getRawUint(tokens, limit, offset, &hash, outStr))
return false;
ushort len;
if (!getRawUshort(tokens, limit, offset, &len, outStr))
return false;
const QChar *chars = (const QChar *)tokens + offset;
if (!getRawStr(tokens, limit, offset, len, outStr))
return false;
uint realhash = ProString::hash(chars, len);
if (realhash != hash)
*outStr += fL1S(" /* Bad hash ") + QString::number(hash) + fL1S(" */");
*outStr += QLatin1Char(')');
return true;
}
static bool getBlock(const ushort *tokens, int limit, int &offset, QString *outStr, int indent);
static bool getSubBlock(const ushort *tokens, int limit, int &offset, QString *outStr, int indent,
const char *scope)
{
*outStr += fL1S("\n /* %1 */ ").arg(offset, 5)
+ QString(indent * 4, QLatin1Char(' '))
+ fL1S("/* ") + fL1S(scope) + fL1S(" */");
uint len;
if (!getUint(tokens, limit, offset, &len, outStr))
return false;
if (len) {
BOUNDS_CHECK(len);
int tmpOff = offset;
offset += len;
forever {
if (!getBlock(tokens, offset, tmpOff, outStr, indent + 1))
break; // Error was already reported, try to continue
if (tmpOff == offset)
break;
*outStr += QLatin1Char('\n') + QString(20 + indent * 4, QLatin1Char(' '))
+ fL1S("/* Warning: Excess tokens follow. */");
}
}
return true;
}
static bool getBlock(const ushort *tokens, int limit, int &offset, QString *outStr, int indent)
{
static const char * const tokNames[] = {
"TokTerminator",
"TokLine",
"TokAssign", "TokAppend", "TokAppendUnique", "TokRemove", "TokReplace",
"TokValueTerminator",
"TokLiteral", "TokHashLiteral", "TokVariable", "TokProperty", "TokEnvVar",
"TokFuncName", "TokArgSeparator", "TokFuncTerminator",
"TokCondition", "TokTestCall",
"TokReturn", "TokBreak", "TokNext",
"TokNot", "TokAnd", "TokOr",
"TokBranch", "TokForLoop",
"TokTestDef", "TokReplaceDef"
};
while (offset != limit) {
*outStr += fL1S("\n /* %1 */").arg(offset, 5)
+ QString(indent * 4, QLatin1Char(' '));
BOUNDS_CHECK(1);
ushort tok = tokens[offset++];
ushort maskedTok = tok & TokMask;
if (maskedTok >= sizeof(tokNames)/sizeof(tokNames[0])
|| (tok & ~(TokNewStr | TokQuoted | TokMask))) {
*outStr += fL1S(" << {invalid token %1}").arg(tok);
return false;
}
*outStr += fL1S(" << H(") + fL1S(tokNames[maskedTok]);
if (tok & TokNewStr)
*outStr += fL1S(" | TokNewStr");
if (tok & TokQuoted)
*outStr += fL1S(" | TokQuoted");
*outStr += QLatin1Char(')');
bool ok;
switch (maskedTok) {
case TokFuncTerminator: // Recursion, but not a sub-block
return true;
case TokArgSeparator:
case TokValueTerminator: // Not recursion
case TokTerminator: // Recursion, and limited by (sub-)block length
case TokCondition:
case TokReturn:
case TokBreak:
case TokNext:
case TokNot:
case TokAnd:
case TokOr:
ok = true;
break;
case TokTestCall:
ok = getBlock(tokens, limit, offset, outStr, indent + 1);
break;
case TokBranch:
ok = getSubBlock(tokens, limit, offset, outStr, indent, "then branch");
if (ok)
ok = getSubBlock(tokens, limit, offset, outStr, indent, "else branch");
break;
default:
switch (maskedTok) {
case TokAssign:
case TokAppend:
case TokAppendUnique:
case TokRemove:
case TokReplace:
// The parameter is the sizehint for the output.
// fallthrough
case TokLine: {
ushort dummy;
ok = getUshort(tokens, limit, offset, &dummy, outStr);
break; }
case TokLiteral:
case TokEnvVar:
ok = getStr(tokens, limit, offset, outStr);
break;
case TokHashLiteral:
case TokVariable:
case TokProperty:
ok = getHashStr(tokens, limit, offset, outStr);
break;
case TokFuncName:
ok = getHashStr(tokens, limit, offset, outStr);
if (ok)
ok = getBlock(tokens, limit, offset, outStr, indent + 1);
break;
case TokForLoop:
ok = getHashStr(tokens, limit, offset, outStr);
if (ok)
ok = getSubBlock(tokens, limit, offset, outStr, indent, "iterator");
if (ok)
ok = getSubBlock(tokens, limit, offset, outStr, indent, "body");
break;
case TokTestDef:
case TokReplaceDef:
ok = getHashStr(tokens, limit, offset, outStr);
if (ok)
ok = getSubBlock(tokens, limit, offset, outStr, indent, "body");
break;
default:
Q_ASSERT(!"unhandled token");
}
}
if (!ok)
return false;
}
return true;
}
QString QMakeParser::formatProBlock(const QString &block)
{
QString outStr;
outStr += fL1S("\n << TS(");
int offset = 0;
getBlock(reinterpret_cast<const ushort *>(block.constData()), block.length(),
offset, &outStr, 0);
outStr += QLatin1Char(')');
return outStr;
}
#endif // PROPARSER_DEBUG
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -93,6 +93,10 @@ public:
void discardFileFromCache(const QString &fileName); void discardFileFromCache(const QString &fileName);
#ifdef PROPARSER_DEBUG
static QString formatProBlock(const QString &block);
#endif
private: private:
enum ScopeNesting { enum ScopeNesting {
NestNone = 0, NestNone = 0,
@@ -127,7 +131,7 @@ private:
}; };
bool read(ProFile *pro, ParseFlags flags); bool read(ProFile *pro, ParseFlags flags);
bool read(ProFile *pro, const QString &content, int line, SubGrammar grammar); void read(ProFile *pro, const QString &content, int line, SubGrammar grammar);
ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok); ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len); ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);
@@ -141,8 +145,12 @@ private:
const ushort *cur, const QString &in); const ushort *cur, const QString &in);
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount); void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc); void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
void warnOperator(const char *msg);
bool failOperator(const char *msg);
bool acceptColon(const char *msg);
void putOperator(ushort *&tokPtr);
void finalizeTest(ushort *&tokPtr); void finalizeTest(ushort *&tokPtr);
void bogusTest(ushort *&tokPtr); void bogusTest(ushort *&tokPtr, const QString &msg);
void enterScope(ushort *&tokPtr, bool special, ScopeState state); void enterScope(ushort *&tokPtr, bool special, ScopeState state);
void leaveScope(ushort *&tokPtr); void leaveScope(ushort *&tokPtr);
void flushCond(ushort *&tokPtr); void flushCond(ushort *&tokPtr);
@@ -150,7 +158,10 @@ private:
void message(int type, const QString &msg) const; void message(int type, const QString &msg) const;
void parseError(const QString &msg) const void parseError(const QString &msg) const
{ message(QMakeParserHandler::ParserError, msg); } {
message(QMakeParserHandler::ParserError, msg);
m_proFile->setOk(false);
}
void languageWarning(const QString &msg) const void languageWarning(const QString &msg) const
{ message(QMakeParserHandler::ParserWarnLanguage, msg); } { message(QMakeParserHandler::ParserWarnLanguage, msg); }
void deprecationWarning(const QString &msg) const void deprecationWarning(const QString &msg) const
@@ -165,7 +176,7 @@ private:
int m_markLine; // Put marker for this line int m_markLine; // Put marker for this line
bool m_inError; // Current line had a parsing error; suppress followup error messages bool m_inError; // Current line had a parsing error; suppress followup error messages
bool m_canElse; // Conditionals met on previous line, but no scope was opened bool m_canElse; // Conditionals met on previous line, but no scope was opened
bool m_invert; // Pending conditional is negated int m_invert; // Pending conditional is negated
enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed
QString m_tmp; // Temporary for efficient toQString QString m_tmp; // Temporary for efficient toQString

View File

@@ -12,7 +12,6 @@ SUBDIRS += \
generichighlighter \ generichighlighter \
profilewriter \ profilewriter \
treeviewfind \ treeviewfind \
ioutils \
qtcprocess \ qtcprocess \
utils \ utils \
filesearch \ filesearch \

View File

@@ -14,7 +14,6 @@ Project {
"externaltool/externaltool.qbs", "externaltool/externaltool.qbs",
"filesearch/filesearch.qbs", "filesearch/filesearch.qbs",
"generichighlighter/generichighlighter.qbs", "generichighlighter/generichighlighter.qbs",
"ioutils/ioutils.qbs",
"profilewriter/profilewriter.qbs", "profilewriter/profilewriter.qbs",
"qml/qml.qbs", "qml/qml.qbs",
"qtcprocess/qtcprocess.qbs", "qtcprocess/qtcprocess.qbs",

View File

@@ -1,5 +0,0 @@
include(../qttest.pri)
INCLUDEPATH += $$IDE_SOURCE_TREE/src/shared
SOURCES += tst_ioutils.cpp \
$$IDE_SOURCE_TREE/src/shared/proparser/ioutils.cpp

View File

@@ -1,11 +0,0 @@
import qbs
QtcAutotest {
name: "IoUtils autotest"
Depends { name: "Qt.core" }
files: [
project.sharedSourcesDir + "/proparser/ioutils.cpp",
"tst_ioutils.cpp"
]
cpp.includePaths: base.concat([project.sharedSourcesDir])
}

View File

@@ -1,84 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include <QtTest>
#include <proparser/ioutils.h>
class tst_IoUtils : public QObject
{
Q_OBJECT
private slots:
void quoteArg_data();
void quoteArg();
};
void tst_IoUtils::quoteArg_data()
{
QTest::addColumn<QString>("in");
QTest::addColumn<QString>("out");
static const struct {
const char * const in;
const char * const out;
} vals[] = {
#ifdef Q_OS_WIN
{ "", "\"\"" },
{ "hallo", "hallo" },
{ "hallo du", "\"hallo du\"" },
{ "hallo\\", "hallo\\" },
{ "hallo du\\", "\"hallo du\"\\" },
{ "ha\"llo", "\"ha\"\\^\"\"llo\"" },
{ "ha\\\"llo", "\"ha\"\\\\\\^\"\"llo\"" },
#else
{ "", "\"\"" },
{ "hallo", "hallo" },
{ "hallo du", "'hallo du'" },
{ "ha'llo", "'ha'\\''llo'" },
#endif
};
for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++)
QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
<< QString::fromLatin1(vals[i].out);
}
void tst_IoUtils::quoteArg()
{
QFETCH(QString, in);
QFETCH(QString, out);
QCOMPARE(QMakeInternal::IoUtils::shellQuote(in), out);
}
QTEST_MAIN(tst_IoUtils)
#include "tst_ioutils.moc"

View File

@@ -180,7 +180,6 @@
:QtSupport__Internal__QtVersionManager.QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' text?='Qt version *' type='QLabel' unnamed='1' visible='1'} :QtSupport__Internal__QtVersionManager.QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' text?='Qt version *' type='QLabel' unnamed='1' visible='1'}
:QtSupport__Internal__QtVersionManager.errorLabel.QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='errorLabel' type='QLabel' visible='1'} :QtSupport__Internal__QtVersionManager.errorLabel.QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='errorLabel' type='QLabel' visible='1'}
:QtSupport__Internal__QtVersionManager.qmake_QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='qmakePath' type='QLabel' visible='1'} :QtSupport__Internal__QtVersionManager.qmake_QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='qmakePath' type='QLabel' visible='1'}
:QtSupport__Internal__QtVersionManager.qtdirList_QTreeWidget {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='qtdirList' type='QTreeWidget' visible='1'}
:QtVersionLabel_KitPage {container=':qt_tabwidget_stackedwidget_QWidget' text='Qt version:' type='QLabel' unnamed='1' visible='1'} :QtVersionLabel_KitPage {container=':qt_tabwidget_stackedwidget_QWidget' text='Qt version:' type='QLabel' unnamed='1' visible='1'}
:Restart required.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Restart required_QMessageBox'} :Restart required.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Restart required_QMessageBox'}
:Restart required_QMessageBox {text='The language change will take effect after a restart of Qt Creator.' type='QMessageBox' unnamed='1' visible='1'} :Restart required_QMessageBox {text='The language change will take effect after a restart of Qt Creator.' type='QMessageBox' unnamed='1' visible='1'}
@@ -225,7 +224,9 @@
:qt_tabwidget_stackedwidget.CppTools__Internal__CompletionSettingsPage_QWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='CppTools__Internal__CompletionSettingsPage' type='QWidget' visible='1'} :qt_tabwidget_stackedwidget.CppTools__Internal__CompletionSettingsPage_QWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='CppTools__Internal__CompletionSettingsPage' type='QWidget' visible='1'}
:qt_tabwidget_stackedwidget.Form_QWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='Help__Internal__GeneralSettingsPage' type='QWidget' visible='1' windowTitle='Form'} :qt_tabwidget_stackedwidget.Form_QWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='Help__Internal__GeneralSettingsPage' type='QWidget' visible='1' windowTitle='Form'}
:qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='QtSupport__Internal__QtVersionManager' type='QtSupport::Internal::QtOptionsPageWidget' visible='1'} :qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='QtSupport__Internal__QtVersionManager' type='QtSupport::Internal::QtOptionsPageWidget' visible='1'}
:qt_tabwidget_stackedwidget_QScrollArea {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' type='QScrollArea' unnamed='1' visible='1'}
:qt_tabwidget_stackedwidget_QWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' type='QWidget' unnamed='1' visible='1'} :qt_tabwidget_stackedwidget_QWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' type='QWidget' unnamed='1' visible='1'}
:qtdirList_QTreeView {container=':qt_tabwidget_stackedwidget_QScrollArea' name='qtdirList' type='QTreeView' visible='1'}
:scrollArea.Details_Utils::DetailsButton {text='Details' type='Utils::DetailsButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :scrollArea.Details_Utils::DetailsButton {text='Details' type='Utils::DetailsButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:scrollArea.Edit build configuration:_QComboBox {leftWidget=':scrollArea.Edit build configuration:_QLabel' type='QComboBox' unnamed='1' visible='1'} :scrollArea.Edit build configuration:_QComboBox {leftWidget=':scrollArea.Edit build configuration:_QLabel' type='QComboBox' unnamed='1' visible='1'}
:scrollArea.Edit build configuration:_QLabel {text='Edit build configuration:' type='QLabel' unnamed='1' visible='1'} :scrollArea.Edit build configuration:_QLabel {text='Edit build configuration:' type='QLabel' unnamed='1' visible='1'}

View File

@@ -72,16 +72,10 @@ def openCmakeProject(projectPath, buildDir):
return __handleCmakeWizardPage__() return __handleCmakeWizardPage__()
def __handleCmakeWizardPage__(): def __handleCmakeWizardPage__():
generatorCombo = waitForObject(":Generator:_QComboBox")
generatorText = "Unix Generator (Desktop 480 GCC)" generatorText = "Unix Generator (Desktop 480 GCC)"
if platform.system() in ('Windows', 'Microsoft'): if platform.system() in ('Windows', 'Microsoft'):
generatorText = "NMake Generator (Desktop 480 MSVC2010)" generatorText = "NMake Generator (Desktop 480 MSVC2010)"
index = generatorCombo.findText(generatorText) selectFromCombo(waitForObject(":Generator:_QComboBox"), generatorText)
if index == -1:
test.warning("No matching CMake generator for found.")
else:
generatorCombo.setCurrentIndex(index)
clickButton(waitForObject(":CMake Wizard.Run CMake_QPushButton")) clickButton(waitForObject(":CMake Wizard.Run CMake_QPushButton"))
try: try:
clickButton(waitForObject(":CMake Wizard.Finish_QPushButton", 60000)) clickButton(waitForObject(":CMake Wizard.Finish_QPushButton", 60000))

View File

@@ -194,8 +194,8 @@ def getQtInformationForQmlProject():
qtVersionStr = str(waitForObject(":Kits_QtVersion_QComboBox").currentText) qtVersionStr = str(waitForObject(":Kits_QtVersion_QComboBox").currentText)
test.log("Kit '%s' uses Qt Version '%s'" % (kit, qtVersionStr)) test.log("Kit '%s' uses Qt Version '%s'" % (kit, qtVersionStr))
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Qt Versions") clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Qt Versions")
treeWidget = waitForObject(":QtSupport__Internal__QtVersionManager.qtdirList_QTreeWidget") treeView = waitForObject(":qtdirList_QTreeView")
if not __selectTreeItemOnBuildAndRun__(treeWidget, qtVersionStr): if not __selectTreeItemOnBuildAndRun__(treeView, qtVersionStr):
test.fatal("Found no matching Qt Version for kit - this shouldn't happen.") test.fatal("Found no matching Qt Version for kit - this shouldn't happen.")
clickButton(waitForObject(":Options.Cancel_QPushButton")) clickButton(waitForObject(":Options.Cancel_QPushButton"))
return None, None, None, None return None, None, None, None

View File

@@ -363,8 +363,8 @@ def __checkParentAccess__(filePath):
# and a list of information of its configured Qt # and a list of information of its configured Qt
def getConfiguredKits(): def getConfiguredKits():
def __retrieveQtVersionName__(target, version): def __retrieveQtVersionName__(target, version):
treeWidget = waitForObject(":QtSupport__Internal__QtVersionManager.qtdirList_QTreeWidget") treeView = waitForObject(":qtdirList_QTreeView")
return treeWidget.currentItem().text(0) return str(treeView.currentIndex().data().toString())
# end of internal function for iterateQtVersions # end of internal function for iterateQtVersions
def __setQtVersionForKit__(kit, kitName, kitsQtVersionName): def __setQtVersionForKit__(kit, kitName, kitsQtVersionName):
treeView = waitForObject(":BuildAndRun_QTreeView") treeView = waitForObject(":BuildAndRun_QTreeView")
@@ -443,13 +443,13 @@ def iterateQtVersions(keepOptionsOpen=False, alreadyOnOptionsDialog=False,
clickItem(":Options_QListView", "Build & Run", 14, 15, 0, Qt.LeftButton) clickItem(":Options_QListView", "Build & Run", 14, 15, 0, Qt.LeftButton)
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Qt Versions") clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Qt Versions")
pattern = re.compile("Qt version (?P<version>.*?) for (?P<target>.*)") pattern = re.compile("Qt version (?P<version>.*?) for (?P<target>.*)")
treeWidget = waitForObject(":QtSupport__Internal__QtVersionManager.qtdirList_QTreeWidget") treeView = waitForObject(":qtdirList_QTreeView")
root = treeWidget.invisibleRootItem() model = treeView.model()
for rootChild in dumpChildren(root): for rootIndex in dumpIndices(model):
rootChildText = str(rootChild.text(0)).replace(".", "\\.").replace("_", "\\_") rootChildText = str(rootIndex.data()).replace(".", "\\.").replace("_", "\\_")
for subChild in dumpChildren(rootChild): for subIndex in dumpIndices(model, rootIndex):
subChildText = str(subChild.text(0)).replace(".", "\\.").replace("_", "\\_") subChildText = str(subIndex.data()).replace(".", "\\.").replace("_", "\\_")
clickItem(treeWidget, ".".join([rootChildText,subChildText]), 5, 5, 0, Qt.LeftButton) clickItem(treeView, ".".join([rootChildText,subChildText]), 5, 5, 0, Qt.LeftButton)
currentText = str(waitForObject(":QtSupport__Internal__QtVersionManager.QLabel").text) currentText = str(waitForObject(":QtSupport__Internal__QtVersionManager.QLabel").text)
matches = pattern.match(currentText) matches = pattern.match(currentText)
if matches: if matches:

View File

@@ -80,8 +80,7 @@ def __checkBuildAndRun__():
qmakePath = which("qmake") qmakePath = which("qmake")
foundQt = [] foundQt = []
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Qt Versions") clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Qt Versions")
__iterateTree__(":QtSupport__Internal__QtVersionManager.qtdirList_QTreeWidget", __iterateTree__(":qtdirList_QTreeView", __qtFunc__, foundQt, qmakePath)
__qtFunc__, foundQt, qmakePath)
test.verify(not qmakePath or len(foundQt) == 1, test.verify(not qmakePath or len(foundQt) == 1,
"Was qmake from %s autodetected? Found %s" % (qmakePath, foundQt)) "Was qmake from %s autodetected? Found %s" % (qmakePath, foundQt))
if foundQt: if foundQt:

View File

@@ -39,7 +39,7 @@ def main():
invokeMenuItem("Tools", "Options...") invokeMenuItem("Tools", "Options...")
waitForObjectItem(":Options_QListView", "Environment") waitForObjectItem(":Options_QListView", "Environment")
clickItem(":Options_QListView", "Environment", 14, 15, 0, Qt.LeftButton) clickItem(":Options_QListView", "Environment", 14, 15, 0, Qt.LeftButton)
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "General") clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Interface")
languageName = testData.field(lang, "language") languageName = testData.field(lang, "language")
if "%1" in languageName: if "%1" in languageName:
country = str(QLocale.countryToString(QLocale(testData.field(lang, "ISO")).country())) country = str(QLocale.countryToString(QLocale(testData.field(lang, "ISO")).country()))