Merge remote-tracking branch 'origin/4.3'

Conflicts:
	src/plugins/debugger/cdb/cdbengine.cpp

Change-Id: Ib9aeccc4162c43e9ee3d85847d96678045625dd0
This commit is contained in:
Eike Ziller
2017-05-09 15:07:30 +02:00
69 changed files with 475 additions and 151 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -1608,6 +1608,10 @@
\li \uicontrol {Open Documents} searches from all open files. \li \uicontrol {Open Documents} searches from all open files.
\li \uicontrol {Clang Query Project} explores the Clang abstract
syntax tree (AST) using AST matcher expressions. For more
information, see \l{Exploring Clang AST}.
\endlist \endlist
\li In the \uicontrol {File pattern} field, specify file patterns to \li In the \uicontrol {File pattern} field, specify file patterns to
@@ -1672,6 +1676,34 @@
\uicontrol {Search engine} field. \uicontrol {Search engine} field.
\endlist \endlist
\section1 Exploring Clang AST
You can use the experimental Clang Refactoring plugin to explore the Clang
AST using AST matcher expressions. For more information about constructing
matcher expressions, see
\l {http://clang.llvm.org/docs/LibASTMatchersReference.html}
{AST Matcher Reference}.
To explore the AST:
\list 1
\li Select \uicontrol Help > \uicontrol {About Plugins} > \uicontrol C++
> \uicontrol {ClangRefactoring} to enable the plugin.
\li Restart \QC to be able to use the plugin.
\li When searching, select \uicontrol {Clang Query Project} in the
\uicontrol {Scope} field.
\li Enter an AST matcher expression in the \uicontrol {Search for}
field.
\endlist
You can view the results of the query as links to code positions in the
\uicontrol {Search Results} output pane.
*/ */
@@ -2473,8 +2505,14 @@
\row \row
\li Move Component into Separate File \li Move Component into Separate File
\li Moves a QML type into a separate file \li Moves a QML type into a separate file. Give the new component a
\li QML type name name and select whether properties are set for the new component
or for the original one.
\image qtcreator-move-component-into-separate-file.png
\li QML type name. This action is also available in the
\uicontrol {Form Editor} in \QMLD.
\row \row
\li Split Initializer \li Split Initializer
\li Reformats a one-line type into a multi-line type. For example, \li Reformats a one-line type into a multi-line type. For example,

View File

@@ -123,12 +123,11 @@
\list 1 \list 1
\li Select \uicontrol {Text Editor} to open Page1Form.ui.qml in the \li Right-click the image and select
text editor tab.
\li Right-click \uicontrol Image and select \uicontrol Refactoring >
\uicontrol {Move Component into Separate File}. \uicontrol {Move Component into Separate File}.
\image qtcreator-move-component-into-separate-file.png
\li In the \uicontrol {Component name} field, enter \e Bubble. \li In the \uicontrol {Component name} field, enter \e Bubble.
\li Deselect the \uicontrol x, \uicontrol y, and \li Deselect the \uicontrol x, \uicontrol y, and

View File

@@ -78,28 +78,40 @@
\endlist \endlist
You can also use ready-made Qt Quick 1 Components (for Qt 4) to create \section1 Using Qt Quick Controls
In Qt 4, ready-made Qt Quick 1 Components were provided for creating
screens with a native look and feel for a particular target platform. screens with a native look and feel for a particular target platform.
Since Qt 5.1, Qt Quick Controls, Dialogs, and Layouts are available for In Qt 5.1, Qt Quick Controls, Dialogs, and Layouts were added for
creating classic desktop-style user interfaces using Qt Quick 2.1. You can creating classic desktop-style user interfaces using Qt Quick 2.1. The
use the Qt Quick Controls Styles to customize Qt Quick Controls. Qt Quick Controls Styles could be used to customize Qt Quick Controls.
Since Qt 5.7, \l {Qt Quick Controls 2} replace Qt Quick Controls 1 and Since Qt 5.7, \l {Qt Quick Controls 2} replace Qt Quick Controls 1 and
Qt Labs Controls. These Controls provide lightweight QML types for creating Qt Labs Controls. They provide lightweight QML types for creating performant
performant user interfaces for embedded and mobile devices. These controls user interfaces for embedded and mobile devices.
achieve improved efficiency by employing a simplified styling architecture
when compared to Qt Quick Controls, on which the module is based. These Qt Quick Controls 2 achieve improved efficiency by employing a simplified
types work in conjunction with Qt Quick and Qt Quick Layouts. \l {Styling Qt Quick Controls 2}{styling architecture} when compared to
Qt Quick Controls, on which the module is based. \QMLD reads the
\c qtquickcontrols2.conf file that specifies the preferred style and some
style-specific arguments. To change the style, select another style from
the list on the toolbar. This enables you to check how your UI looks when
using the available styles.
For an example of defining your own style and using it in \QMLD, see
\l {Qt Quick Controls 2 - Flat Style}.
Qt Quick Controls 2 work in conjunction with Qt Quick and Qt Quick Layouts.
The \QC project wizards create Qt Quick applications that use Qt Quick
2 types or Qt Quick Controls 2 types.
Even if you use Qt Quick Controls 2, you can still write cross-platform
applications, by using different sets of QML files for each platform.
Some ready-made controls, such as a gauge, dial, status indicator, and Some ready-made controls, such as a gauge, dial, status indicator, and
tumbler, are provided by the \l {Qt Quick Extras} module. tumbler, are provided by the \l {Qt Quick Extras} module.
The \QC project wizards create Qt Quick applications that use Qt Quick
Components or Controls.
Even if you use the Qt Quick Components, you can still write cross-platform
applications, by using different sets of QML files for each platform.
\section1 Creating Components in Qt Quick Designer \section1 Creating Components in Qt Quick Designer
\list 1 \list 1

View File

@@ -135,5 +135,6 @@
application for example to mockup C++ items, then you can use \c{QML_DESIGNER_IMPORT_PATH} application for example to mockup C++ items, then you can use \c{QML_DESIGNER_IMPORT_PATH}
in the \c{.pro} file. in the \c{.pro} file.
Modules in the import paths defined in \c{QML_DESIGNER_IMPORT_PATH} will be used only in \QMLD. Modules in the import paths defined in \c{QML_DESIGNER_IMPORT_PATH} will be used only in \QMLD.
For an example, see \l {Qt Quick Controls 2 - Contact List}.
*/ */

View File

@@ -45,19 +45,6 @@
The QML files in the project folder are displayed in \uicontrol {QML Components} The QML files in the project folder are displayed in \uicontrol {QML Components}
in the \uicontrol Library. in the \uicontrol Library.
You can also use ready-made Qt Quick 1 Components (for Qt 4) to create
screens with a native look and feel for a particular target platform.
Since Qt 5.1, Qt Quick Controls, Dialogs, and Layouts are available for
creating classic desktop-style user interfaces using Qt Quick 2.1. You can
use the Qt Quick Controls Styles to customize Qt Quick Controls.
Since Qt 5.7, \l {Qt Quick Controls 2} replace Qt Quick Controls 1 and
Qt Labs Controls. These controls provide lightweight QML types for creating
performant user interfaces for embedded and mobile devices. These controls
achieve improved efficiency by employing a simplified styling architecture
when compared to Qt Quick Controls, on which the module is based. These
types work in conjunction with Qt Quick and Qt Quick Layouts.
\section1 Adding Components to Screens \section1 Adding Components to Screens
\list 1 \list 1
@@ -72,6 +59,8 @@
\endlist \endlist
For more information about the ready-made components available, see
\l {Using Qt Quick Controls}.
\section1 Using Data Models \section1 Using Data Models
@@ -338,7 +327,7 @@
example, you can use states to create two screens. example, you can use states to create two screens.
To add states, click the empty slot in the \uicontrol States pane. Then modify the To add states, click the empty slot in the \uicontrol States pane. Then modify the
new state in the \uicontrol {Form Editor}. new state in the \uicontrol {Form Editor} or the \uicontrol Properties pane.
\image qmldesigner-states.png "States pane" \image qmldesigner-states.png "States pane"
@@ -402,6 +391,18 @@
\endlist \endlist
\section2 Using SCXML State Machines
To use QML and \QMLD together with an SCXML state machine, add states and
bind them to the state machine in the \uicontrol Backends tab, as described
in \l {Managing C++ Backend Objects}.
In the \uicontrol States pane, you can edit the \c when condition of states
to map QML states to the states of the SCXML state machine. For an example,
see \l {Qt SCXML Traffic Light QML Example (Dynamic)}.
\image qmldesigner-states-when-condition.png
\section1 Animating Screens \section1 Animating Screens
To make movement between states smooth, you can specify transitions. You can To make movement between states smooth, you can specify transitions. You can

View File

@@ -1320,9 +1320,10 @@ class DumperBase:
derefValue.name = '*' derefValue.name = '*'
self.putItem(derefValue) self.putItem(derefValue)
self.currentChildType = savedCurrentChildType self.currentChildType = savedCurrentChildType
self.putOriginalAddress(value.pointer()) self.putAddress(value.address())
def putFormattedPointerX(self, value): def putFormattedPointerX(self, value):
self.putOriginalAddress(value.address())
#warn("PUT FORMATTED: %s" % value) #warn("PUT FORMATTED: %s" % value)
pointer = value.pointer() pointer = value.pointer()
#warn('POINTER: 0x%x' % pointer) #warn('POINTER: 0x%x' % pointer)
@@ -2671,7 +2672,6 @@ class DumperBase:
typeName = typeobj.name typeName = typeobj.name
self.addToCache(typeobj) # Fill type cache self.addToCache(typeobj) # Fill type cache
self.putAddress(value.address())
if not value.lIsInScope: if not value.lIsInScope:
self.putSpecialValue('optimizedout') self.putSpecialValue('optimizedout')
@@ -2685,6 +2685,10 @@ class DumperBase:
# Try on possibly typedefed type first. # Try on possibly typedefed type first.
if self.tryPutPrettyItem(typeName, value): if self.tryPutPrettyItem(typeName, value):
if typeobj.code == TypeCodePointer:
self.putOriginalAddress(value.address())
else:
self.putAddress(value.address())
return return
if typeobj.code == TypeCodeTypedef: if typeobj.code == TypeCodeTypedef:
@@ -2697,6 +2701,8 @@ class DumperBase:
self.putFormattedPointer(value) self.putFormattedPointer(value)
return return
self.putAddress(value.address())
if typeobj.code == TypeCodeFunction: if typeobj.code == TypeCodeFunction:
#warn('FUNCTION VALUE: %s' % value) #warn('FUNCTION VALUE: %s' % value)
self.putType(typeobj) self.putType(typeobj)
@@ -3142,7 +3148,7 @@ class DumperBase:
if self.dumper.isInt(other): if self.dumper.isInt(other):
stripped = self.type.stripTypedefs() stripped = self.type.stripTypedefs()
if stripped.code == TypeCodePointer: if stripped.code == TypeCodePointer:
address = self.pointer() + stripped.dereference().size() address = self.pointer() + stripped.dereference().size() * other
val = self.dumper.Value(self.dumper) val = self.dumper.Value(self.dumper)
val.laddress = None val.laddress = None
val.ldata = bytes(struct.pack(self.dumper.packCode + 'Q', address)) val.ldata = bytes(struct.pack(self.dumper.packCode + 'Q', address))

View File

@@ -349,3 +349,16 @@ def qdump__QtcDumperTest_PointerArray(d, value):
for i in d.childRange(): for i in d.childRange():
d.putSubItem(i, foos[i]) d.putSubItem(i, foos[i])
def qdump__QtcDumperTest_BufArray(d, value):
maxItems = 1000
buffer = value['buffer']
count = int(value['count'])
objsize = int(value['objSize'])
valueType = value.type.templateArgument(0)
d.putItemCount(count, maxItems)
d.putNumChild(count)
if d.isExpanded():
with Children(d, count, maxNumChild=maxItems, childType=valueType):
for i in d.childRange():
d.putSubItem(i, (buffer + (i * objsize)).dereference().cast(valueType))

View File

@@ -45,4 +45,9 @@ void DummyContextObject::setParentDummy(QObject *parentDummy)
} }
} }
bool DummyContextObject::runningInDesigner() const
{
return true;
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -35,12 +35,14 @@ class DummyContextObject : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QObject * parent READ parentDummy WRITE setParentDummy NOTIFY parentDummyChanged DESIGNABLE false FINAL) Q_PROPERTY(QObject * parent READ parentDummy WRITE setParentDummy NOTIFY parentDummyChanged DESIGNABLE false FINAL)
Q_PROPERTY(bool runningInDesigner READ runningInDesigner FINAL)
public: public:
explicit DummyContextObject(QObject *parent = 0); explicit DummyContextObject(QObject *parent = 0);
QObject *parentDummy() const; QObject *parentDummy() const;
void setParentDummy(QObject *parentDummy); void setParentDummy(QObject *parentDummy);
bool runningInDesigner() const;
signals: signals:
void parentDummyChanged(); void parentDummyChanged();

View File

@@ -259,7 +259,7 @@ static inline void splitCommand(PCSTR args, Inserter it)
template<class StringContainer> template<class StringContainer>
static inline StringContainer commandTokens(PCSTR args, int *token = 0) static inline StringContainer commandTokens(PCSTR args, int *token = 0)
{ {
typedef StringContainer::iterator ContainerIterator; typedef typename StringContainer::iterator ContainerIterator;
if (token) if (token)
*token = -1; // Handled as 'display' in engine, so that user can type commands *token = -1; // Handled as 'display' in engine, so that user can type commands

View File

@@ -75,7 +75,7 @@ void AbstractSshChannel::requestSessionStart()
m_sendFacility.sendSessionPacket(m_localChannel, initialWindowSize(), maxPacketSize()); m_sendFacility.sendSessionPacket(m_localChannel, initialWindowSize(), maxPacketSize());
setChannelState(SessionRequested); setChannelState(SessionRequested);
m_timeoutTimer.start(ReplyTimeout); m_timeoutTimer.start(ReplyTimeout);
} catch (const Botan::Exception &e) { } catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what()); qCWarning(sshLog, "Botan error: %s", e.what());
closeChannel(); closeChannel();
} }
@@ -86,7 +86,7 @@ void AbstractSshChannel::sendData(const QByteArray &data)
try { try {
m_sendBuffer += data; m_sendBuffer += data;
flushSendBuffer(); flushSendBuffer();
} catch (const Botan::Exception &e) { } catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what()); qCWarning(sshLog, "Botan error: %s", e.what());
closeChannel(); closeChannel();
} }

View File

@@ -91,7 +91,7 @@ void SshChannelManager::handleChannelOpen(const SshIncomingPacket &packet)
try { try {
m_sendFacility.sendChannelOpenFailurePacket(channelOpen.remoteChannel, reason, m_sendFacility.sendChannelOpenFailurePacket(channelOpen.remoteChannel, reason,
QByteArray()); QByteArray());
} catch (const Botan::Exception &e) { } catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what()); qCWarning(sshLog, "Botan error: %s", e.what());
} }
return; return;

View File

@@ -200,7 +200,7 @@ int SshConnection::closeAllChannels()
{ {
try { try {
return d->m_channelManager->closeAllChannels(Internal::SshChannelManager::CloseAllRegular); return d->m_channelManager->closeAllChannels(Internal::SshChannelManager::CloseAllRegular);
} catch (const Botan::Exception &e) { } catch (const std::exception &e) {
qCWarning(Internal::sshLog, "%s: %s", Q_FUNC_INFO, e.what()); qCWarning(Internal::sshLog, "%s: %s", Q_FUNC_INFO, e.what());
return -1; return -1;
} }
@@ -346,7 +346,7 @@ void SshConnectionPrivate::handleIncomingData()
} catch (const SshClientException &e) { } catch (const SshClientException &e) {
closeConnection(SSH_DISCONNECT_BY_APPLICATION, e.error, "", closeConnection(SSH_DISCONNECT_BY_APPLICATION, e.error, "",
e.errorString); e.errorString);
} catch (const Botan::Exception &e) { } catch (const std::exception &e) {
closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshInternalError, "", closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshInternalError, "",
tr("Botan library exception: %1").arg(QString::fromLatin1(e.what()))); tr("Botan library exception: %1").arg(QString::fromLatin1(e.what())));
} }

View File

@@ -272,10 +272,7 @@ bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &p
Q_FUNC_INFO); Q_FUNC_INFO);
return false; return false;
} }
} catch (const Exception &ex) { } catch (const std::exception &ex) {
error = QLatin1String(ex.what());
return false;
} catch (const Decoding_Error &ex) {
error = QLatin1String(ex.what()); error = QLatin1String(ex.what());
return false; return false;
} }
@@ -360,10 +357,7 @@ bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray
sequence.discard_remaining(); sequence.discard_remaining();
sequence.verify_end(); sequence.verify_end();
} catch (const Exception &ex) { } catch (const std::exception &ex) {
error = QLatin1String(ex.what());
return false;
} catch (const Decoding_Error &ex) {
error = QLatin1String(ex.what()); error = QLatin1String(ex.what());
return false; return false;
} }

View File

@@ -103,7 +103,7 @@ void SshDirectTcpIpTunnel::initialize()
d->m_originatingHost.toUtf8(), d->m_originatingPort); d->m_originatingHost.toUtf8(), d->m_originatingPort);
d->setChannelState(AbstractSshChannel::SessionRequested); d->setChannelState(AbstractSshChannel::SessionRequested);
d->m_timeoutTimer.start(d->ReplyTimeout); d->m_timeoutTimer.start(d->ReplyTimeout);
} catch (const Botan::Exception &e) { // Won't happen, but let's play it safe. } catch (const std::exception &e) { // Won't happen, but let's play it safe.
qCWarning(sshLog, "Botan error: %s", e.what()); qCWarning(sshLog, "Botan error: %s", e.what());
d->closeChannel(); d->closeChannel();
} }

View File

@@ -45,7 +45,7 @@ void SshForwardedTcpIpTunnelPrivate::handleOpenSuccessInternal()
try { try {
m_sendFacility.sendChannelOpenConfirmationPacket(remoteChannel(), localChannelId(), m_sendFacility.sendChannelOpenConfirmationPacket(remoteChannel(), localChannelId(),
initialWindowSize(), maxPacketSize()); initialWindowSize(), maxPacketSize());
} catch (const Botan::Exception &e) { // Won't happen, but let's play it safe. } catch (const std::exception &e) { // Won't happen, but let's play it safe.
qCWarning(sshLog, "Botan error: %s", e.what()); qCWarning(sshLog, "Botan error: %s", e.what());
closeChannel(); closeChannel();
} }

View File

@@ -77,6 +77,8 @@ void SshKeyCreationDialog::keyTypeChanged()
keySizes << QLatin1String("1024") << QLatin1String("2048") << QLatin1String("4096"); keySizes << QLatin1String("1024") << QLatin1String("2048") << QLatin1String("4096");
else if (m_ui->ecdsa->isChecked()) else if (m_ui->ecdsa->isChecked())
keySizes << QLatin1String("256") << QLatin1String("384") << QLatin1String("521"); keySizes << QLatin1String("256") << QLatin1String("384") << QLatin1String("521");
else if (m_ui->dsa->isChecked())
keySizes << QLatin1String("1024");
m_ui->comboBox->addItems(keySizes); m_ui->comboBox->addItems(keySizes);
if (!keySizes.isEmpty()) if (!keySizes.isEmpty())
m_ui->comboBox->setCurrentIndex(0); m_ui->comboBox->setCurrentIndex(0);

View File

@@ -83,7 +83,7 @@ bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, int ke
generateOpenSslPublicKeyString(key); generateOpenSslPublicKeyString(key);
} }
return true; return true;
} catch (const Exception &e) { } catch (const std::exception &e) {
m_error = tr("Error generating key: %1").arg(QString::fromLatin1(e.what())); m_error = tr("Error generating key: %1").arg(QString::fromLatin1(e.what()));
return false; return false;
} }

View File

@@ -209,7 +209,7 @@ void SshRemoteProcess::sendSignal(Signal signal)
QSSH_ASSERT_AND_RETURN(signalString); QSSH_ASSERT_AND_RETURN(signalString);
d->m_sendFacility.sendChannelSignalPacket(d->remoteChannel(), signalString); d->m_sendFacility.sendChannelSignalPacket(d->remoteChannel(), signalString);
} }
} catch (const Botan::Exception &e) { } catch (const std::exception &e) {
setErrorString(QString::fromLatin1(e.what())); setErrorString(QString::fromLatin1(e.what()));
d->closeChannel(); d->closeChannel();
} }

View File

@@ -86,7 +86,7 @@ void SshTcpIpForwardServer::initialize()
emit stateChanged(Initializing); emit stateChanged(Initializing);
d->m_sendFacility.sendTcpIpForwardPacket(d->m_bindAddress.toUtf8(), d->m_bindPort); d->m_sendFacility.sendTcpIpForwardPacket(d->m_bindAddress.toUtf8(), d->m_bindPort);
d->m_timeoutTimer.start(d->ReplyTimeout); d->m_timeoutTimer.start(d->ReplyTimeout);
} catch (const Botan::Exception &e) { } catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what()); qCWarning(sshLog, "Botan error: %s", e.what());
d->m_timeoutTimer.stop(); d->m_timeoutTimer.stop();
setClosed(); setClosed();
@@ -105,7 +105,7 @@ void SshTcpIpForwardServer::close()
d->m_sendFacility.sendCancelTcpIpForwardPacket(d->m_bindAddress.toUtf8(), d->m_sendFacility.sendCancelTcpIpForwardPacket(d->m_bindAddress.toUtf8(),
d->m_bindPort); d->m_bindPort);
d->m_timeoutTimer.start(d->ReplyTimeout); d->m_timeoutTimer.start(d->ReplyTimeout);
} catch (const Botan::Exception &e) { } catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what()); qCWarning(sshLog, "Botan error: %s", e.what());
d->m_timeoutTimer.stop(); d->m_timeoutTimer.stop();
setClosed(); setClosed();

View File

@@ -61,7 +61,9 @@
#include <QDirIterator> #include <QDirIterator>
#include <QFileInfo> #include <QFileInfo>
#include <QHostAddress> #include <QHostAddress>
#include <QLoggingCategory>
#include <QProcess> #include <QProcess>
#include <QRegularExpression>
#include <QSettings> #include <QSettings>
#include <QStringList> #include <QStringList>
#include <QTcpSocket> #include <QTcpSocket>
@@ -72,6 +74,10 @@
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace Utils; using namespace Utils;
namespace {
Q_LOGGING_CATEGORY(avdConfigLog, "qtc.android.androidconfig")
}
namespace Android { namespace Android {
using namespace Internal; using namespace Internal;
@@ -114,6 +120,7 @@ namespace {
const QLatin1String changeTimeStamp("ChangeTimeStamp"); const QLatin1String changeTimeStamp("ChangeTimeStamp");
const QLatin1String sdkToolsVersionKey("Pkg.Revision"); const QLatin1String sdkToolsVersionKey("Pkg.Revision");
const QLatin1String ndkRevisionKey("Pkg.Revision");
static QString sdkSettingsFileName() static QString sdkSettingsFileName()
{ {
@@ -758,6 +765,53 @@ FileName AndroidConfig::ndkLocation() const
return m_ndkLocation; return m_ndkLocation;
} }
QVersionNumber AndroidConfig::ndkVersion() const
{
QVersionNumber version;
if (!m_ndkLocation.exists()) {
qCDebug(avdConfigLog) << "Can not find ndk version. Check NDK path."
<< m_ndkLocation.toString();
return version;
}
Utils::FileName ndkPropertiesPath(m_ndkLocation);
ndkPropertiesPath.appendPath("source.properties");
if (ndkPropertiesPath.exists()) {
// source.properties files exists in NDK version > 11
QSettings settings(ndkPropertiesPath.toString(), QSettings::IniFormat);
auto versionStr = settings.value(ndkRevisionKey).toString();
version = QVersionNumber::fromString(versionStr);
} else {
// No source.properties. There should be a file named RELEASE.TXT
Utils::FileName ndkReleaseTxtPath(m_ndkLocation);
ndkReleaseTxtPath.appendPath("RELEASE.TXT");
Utils::FileReader reader;
QString errorString;
if (reader.fetch(ndkReleaseTxtPath.toString(), &errorString)) {
// RELEASE.TXT contains the ndk version in either of the following formats:
// r6a
// r10e (64 bit)
QString content = QString::fromUtf8(reader.data());
QRegularExpression re("(r)(?<major>[0-9]{1,2})(?<minor>[a-z]{1,1})");
QRegularExpressionMatch match = re.match(content);
if (match.hasMatch()) {
QString major = match.captured("major");
QString minor = match.captured("minor");
// Minor version: a = 0, b = 1, c = 2 and so on.
// Int equivalent = minorVersionChar - 'a'. i.e. minorVersionChar - 97.
version = QVersionNumber::fromString(QString("%1.%2.0").arg(major)
.arg((int)minor[0].toLatin1() - 97));
} else {
qCDebug(avdConfigLog) << "Can not find ndk version. Can not parse RELEASE.TXT."
<< content;
}
} else {
qCDebug(avdConfigLog) << "Can not find ndk version." << errorString;
}
}
return version;
}
void AndroidConfig::setNdkLocation(const FileName &ndkLocation) void AndroidConfig::setNdkLocation(const FileName &ndkLocation)
{ {
m_ndkLocation = ndkLocation; m_ndkLocation = ndkLocation;

View File

@@ -115,6 +115,7 @@ public:
QVersionNumber sdkToolsVersion() const; QVersionNumber sdkToolsVersion() const;
Utils::FileName ndkLocation() const; Utils::FileName ndkLocation() const;
QVersionNumber ndkVersion() const;
void setNdkLocation(const Utils::FileName &ndkLocation); void setNdkLocation(const Utils::FileName &ndkLocation);
Utils::FileName antLocation() const; Utils::FileName antLocation() const;

View File

@@ -104,8 +104,10 @@ RunControl *AndroidDebugSupport::createDebugRunControl(RunConfiguration *runConf
params.displayName = AndroidManager::packageName(target); params.displayName = AndroidManager::packageName(target);
params.remoteSetupNeeded = true; params.remoteSetupNeeded = true;
params.useContinueInsteadOfRun = true; params.useContinueInsteadOfRun = true;
if (!Utils::HostOsInfo::isWindowsHost()) // Workaround for NDK 11c(b?) if (!Utils::HostOsInfo::isWindowsHost() &&
AndroidConfigurations::currentConfig().ndkVersion() >= QVersionNumber(11, 0, 0)) {
params.useTargetAsync = true; params.useTargetAsync = true;
}
auto aspect = runConfig->extraAspect<DebuggerRunConfigurationAspect>(); auto aspect = runConfig->extraAspect<DebuggerRunConfigurationAspect>();

View File

@@ -161,7 +161,7 @@ AndroidConfig::CreateAvdInfo AndroidToolManager::createAvdImpl(AndroidConfig::Cr
proc.setProcessEnvironment(env.toProcessEnvironment()); proc.setProcessEnvironment(env.toProcessEnvironment());
QStringList arguments; QStringList arguments;
arguments << QLatin1String("create") << QLatin1String("avd") arguments << QLatin1String("create") << QLatin1String("avd")
<< QLatin1String("-t") << info.target.name << QLatin1String("-t") << AndroidConfig::apiLevelNameFor(info.target)
<< QLatin1String("-n") << info.name << QLatin1String("-n") << info.name
<< QLatin1String("-b") << info.abi; << QLatin1String("-b") << info.abi;
if (info.sdcardSize > 0) if (info.sdcardSize > 0)

View File

@@ -531,8 +531,8 @@ void CMakeProject::createGeneratedCodeModelSupport()
= Utils::transform<QSet>(factories, [](const ExtraCompilerFactory *f) { return f->sourceTag(); }); = Utils::transform<QSet>(factories, [](const ExtraCompilerFactory *f) { return f->sourceTag(); });
// Find all files generated by any of the extra compilers, in a rather crude way. // Find all files generated by any of the extra compilers, in a rather crude way.
const QStringList fileList = files(SourceFiles, [&fileExtensions](const FileNode *fn) { const QStringList fileList = files(SourceFiles, [&fileExtensions](const Node *n) {
const QString fp = fn->filePath().toString(); const QString fp = n->filePath().toString();
const int pos = fp.lastIndexOf('.'); const int pos = fp.lastIndexOf('.');
return pos >= 0 && fileExtensions.contains(fp.mid(pos + 1)); return pos >= 0 && fileExtensions.contains(fp.mid(pos + 1));
}); });

View File

@@ -735,7 +735,7 @@ void ServerModeReader::addHeaderNodes(ProjectNode *root, const QList<FileNode *>
const int count = seenHeaders.count(); const int count = seenHeaders.count();
seenHeaders.insert(fn->filePath()); seenHeaders.insert(fn->filePath());
if (seenHeaders.count() != count) { if (seenHeaders.count() != count) {
auto node = new FileNode(*fn); auto node = fn->clone();
node->setEnabled(false); node->setEnabled(false);
headerNode->addNestedNode(node); headerNode->addNestedNode(node);
} }

View File

@@ -309,7 +309,7 @@ void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<cons
return Utils::contains(allIncludePaths, [fn](const FileName &inc) { return fn->filePath().isChildOf(inc); }); return Utils::contains(allIncludePaths, [fn](const FileName &inc) { return fn->filePath().isChildOf(inc); });
}); });
QList<FileNode *> fileNodes = m_files + Utils::transform(missingHeaders, [](const FileNode *fn) { return new FileNode(*fn); }); QList<FileNode *> fileNodes = m_files + Utils::transform(missingHeaders, [](const FileNode *fn) { return fn->clone(); });
root->addNestedNodes(fileNodes, m_parameters.sourceDirectory); root->addNestedNodes(fileNodes, m_parameters.sourceDirectory);
m_files.clear(); // Some of the FileNodes in files() were deleted! m_files.clear(); // Some of the FileNodes in files() were deleted!

View File

@@ -380,8 +380,6 @@ void HelpManager::setupHelpManager()
// create the help engine // create the help engine
d->m_helpEngine = new QHelpEngineCore(collectionFilePath(), m_instance); d->m_helpEngine = new QHelpEngineCore(collectionFilePath(), m_instance);
d->m_helpEngine->setAutoSaveFilter(false);
d->m_helpEngine->setCurrentFilter(tr("Unfiltered"));
d->m_helpEngine->setupData(); d->m_helpEngine->setupData();
foreach (const QString &filePath, d->documentationFromInstaller()) foreach (const QString &filePath, d->documentationFromInstaller())

View File

@@ -521,6 +521,10 @@ bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage
const QFileInfo extensionFi(CdbEngine::extensionLibraryName(cdbIs64Bit)); const QFileInfo extensionFi(CdbEngine::extensionLibraryName(cdbIs64Bit));
if (!extensionFi.isFile()) { if (!extensionFi.isFile()) {
*errorMessage = tr("Internal error: The extension %1 cannot be found.\n" *errorMessage = tr("Internal error: The extension %1 cannot be found.\n"
"If you have updated Qt Creator via Maintenance Tool you may "
"need to rerun the Tool and select \"Add or remove components\""
"and then select the\n"
"Qt > Tools > Qt Creator > Qt Creator CDB Debugger Support component.\n"
"If you build Qt Creator from sources and want to use a cdb executable" "If you build Qt Creator from sources and want to use a cdb executable"
"with another bitness than your Qt Creator build,\n" "with another bitness than your Qt Creator build,\n"
"you will need to build a separate cdbextension with the " "you will need to build a separate cdbextension with the "

View File

@@ -799,6 +799,7 @@ static bool parseOutput(const QSharedPointer<GerritParameters> &parameters,
} else { } else {
adaptedOutput = output; adaptedOutput = output;
// Strip first line, which is )]}' // Strip first line, which is )]}'
if (adaptedOutput.startsWith(')'))
adaptedOutput.remove(0, adaptedOutput.indexOf("\n")); adaptedOutput.remove(0, adaptedOutput.indexOf("\n"));
} }
bool res = true; bool res = true;

View File

@@ -304,10 +304,8 @@ QHelpEngine &LocalHelpManager::helpEngine()
{ {
if (!m_guiEngine) { if (!m_guiEngine) {
QMutexLocker _(&m_guiMutex); QMutexLocker _(&m_guiMutex);
if (!m_guiEngine) { if (!m_guiEngine)
m_guiEngine = new QHelpEngine(QString()); m_guiEngine = new QHelpEngine(QString());
m_guiEngine->setAutoSaveFilter(false);
}
} }
return *m_guiEngine; return *m_guiEngine;
} }

View File

@@ -168,8 +168,8 @@ bool NimProject::supportsKit(Kit *k, QString *errorMessage) const
FileNameList NimProject::nimFiles() const FileNameList NimProject::nimFiles() const
{ {
const QStringList nim = files(AllFiles, [](const ProjectExplorer::FileNode *fn) { const QStringList nim = files(AllFiles, [](const ProjectExplorer::Node *n) {
return fn->filePath().endsWith(".nim"); return n->filePath().endsWith(".nim");
}); });
return Utils::transform(nim, [](const QString &fp) { return Utils::FileName::fromString(fp); }); return Utils::transform(nim, [](const QString &fp) { return Utils::FileName::fromString(fp); });
} }

View File

@@ -606,24 +606,36 @@ bool Abi::operator == (const Abi &other) const
bool Abi::isCompatibleWith(const Abi &other) const bool Abi::isCompatibleWith(const Abi &other) const
{ {
bool isCompat = (architecture() == other.architecture() || other.architecture() == Abi::UnknownArchitecture) // Generic match: If stuff is identical or the other side is unknown, then this is a match.
&& (os() == other.os() || other.os() == Abi::UnknownOS) bool isCompat = (architecture() == other.architecture() || other.architecture() == UnknownArchitecture)
&& (osFlavor() == other.osFlavor() || other.osFlavor() == Abi::UnknownFlavor) && (os() == other.os() || other.os() == UnknownOS)
&& (binaryFormat() == other.binaryFormat() || other.binaryFormat() == Abi::UnknownFormat) && (osFlavor() == other.osFlavor() || other.osFlavor() == UnknownFlavor)
&& (binaryFormat() == other.binaryFormat() || other.binaryFormat() == UnknownFormat)
&& ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0); && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0);
// *-linux-generic-* is compatible with *-linux-* (both ways): This is for the benefit of // *-linux-generic-* is compatible with *-linux-* (both ways): This is for the benefit of
// people building Qt themselves using e.g. a meego toolchain. // people building Qt themselves using e.g. a meego toolchain.
// //
// We leave it to the specific targets to catch filter out the tool chains that do not // We leave it to the specific targets to filter out the tool chains that do not
// work for them. // work for them.
if (!isCompat && (architecture() == other.architecture() || other.architecture() == Abi::UnknownArchitecture) if (!isCompat && (architecture() == other.architecture() || other.architecture() == UnknownArchitecture)
&& ((os() == other.os()) && (os() == LinuxOS)) && ((os() == other.os()) && (os() == LinuxOS))
&& (osFlavor() == GenericLinuxFlavor || other.osFlavor() == GenericLinuxFlavor) && (osFlavor() == GenericLinuxFlavor || other.osFlavor() == GenericLinuxFlavor)
&& (binaryFormat() == other.binaryFormat() || other.binaryFormat() == Abi::UnknownFormat) && (binaryFormat() == other.binaryFormat() || other.binaryFormat() == UnknownFormat)
&& ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0)) && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0)) {
isCompat = true; isCompat = true;
if (osFlavor() == AndroidLinuxFlavor || other.osFlavor() == AndroidLinuxFlavor) }
isCompat = (osFlavor() == other.osFlavor() && architecture() == other.architecture());
// Make Android matching more strict than the generic Linux matches so far:
if (isCompat && (osFlavor() == AndroidLinuxFlavor || other.osFlavor() == AndroidLinuxFlavor))
isCompat = (architecture() == other.architecture()) && (osFlavor() == other.osFlavor());
// MSVC2017 is compatible with MSVC2015
if (!isCompat
&& ((osFlavor() == WindowsMsvc2015Flavor && other.osFlavor() == WindowsMsvc2017Flavor)
|| (osFlavor() == WindowsMsvc2017Flavor && other.osFlavor() == WindowsMsvc2015Flavor))) {
isCompat = true;
}
return isCompat; return isCompat;
} }

View File

@@ -418,6 +418,10 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
delete tab.runControl; delete tab.runControl;
handleOldOutput(tab.window); handleOldOutput(tab.window);
tab.runControl = rc; tab.runControl = rc;
// Update the title.
m_tabWidget->setTabText(tabIndex, rc->displayName());
tab.window->setFormatter(nullptr); tab.window->setFormatter(nullptr);
tab.window->scrollToBottom(); tab.window->scrollToBottom();
if (debug) if (debug)

View File

@@ -548,7 +548,7 @@ Project::RestoreResult Project::restoreSettings(QString *errorMessage)
} }
QStringList Project::files(Project::FilesMode fileMode, QStringList Project::files(Project::FilesMode fileMode,
const std::function<bool (const FileNode *)> &filter) const const std::function<bool(const Node *)> &filter) const
{ {
QStringList result; QStringList result;
@@ -556,17 +556,19 @@ QStringList Project::files(Project::FilesMode fileMode,
return result; return result;
QSet<QString> alreadySeen; QSet<QString> alreadySeen;
rootProjectNode()->forEachNode([&](const FileNode *fn) { rootProjectNode()->forEachGenericNode([&](const Node *n) {
if (filter && !filter(fn)) const QString path = n->filePath().toString();
return;
const QString path = fn->filePath().toString();
const int count = alreadySeen.count(); const int count = alreadySeen.count();
alreadySeen.insert(path); alreadySeen.insert(path);
if (count == alreadySeen.count()) if (count == alreadySeen.count())
return; // skip duplicates return; // skip duplicates
if (!n->listInProject())
return;
if (filter && !filter(n))
return;
if ((fileMode == AllFiles) if ((fileMode == AllFiles)
|| (fileMode == SourceFiles && !fn->isGenerated()) || (fileMode == SourceFiles && !n->isGenerated())
|| (fileMode == GeneratedFiles && fn->isGenerated())) || (fileMode == GeneratedFiles && n->isGenerated()))
result.append(path); result.append(path);
}); });
return result; return result;

View File

@@ -47,8 +47,8 @@ namespace ProjectExplorer {
class BuildInfo; class BuildInfo;
class ContainerNode; class ContainerNode;
class EditorConfiguration; class EditorConfiguration;
class FileNode;
class NamedWidget; class NamedWidget;
class Node;
class ProjectImporter; class ProjectImporter;
class ProjectNode; class ProjectNode;
class ProjectPrivate; class ProjectPrivate;
@@ -133,7 +133,7 @@ public:
AllFiles = SourceFiles | GeneratedFiles AllFiles = SourceFiles | GeneratedFiles
}; };
QStringList files(FilesMode fileMode, QStringList files(FilesMode fileMode,
const std::function<bool(const FileNode *)> &filter = {}) const; const std::function<bool(const Node *)> &filter = {}) const;
virtual QStringList filesGeneratedFrom(const QString &sourceFile) const; virtual QStringList filesGeneratedFrom(const QString &sourceFile) const;
static QString makeUnique(const QString &preferredName, const QStringList &usedNames); static QString makeUnique(const QString &preferredName, const QStringList &usedNames);

View File

@@ -127,6 +127,22 @@ void Node::setPriority(int p)
m_priority = p; m_priority = p;
} }
void Node::setListInProject(bool l)
{
if (l)
m_flags |= FlagListInProject;
else
m_flags &= ~FlagListInProject;
}
void Node::setIsGenerated(bool g)
{
if (g)
m_flags |= FlagIsGenerated;
else
m_flags &= ~FlagIsGenerated;
}
void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line) void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line)
{ {
if (m_filePath == path && m_line == line) if (m_filePath == path && m_line == line)
@@ -148,6 +164,14 @@ int Node::priority() const
return m_priority; return m_priority;
} }
/*!
Returns \c true if the Node should be listed as part of the projects file list.
*/
bool Node::listInProject() const
{
return m_flags.testFlag(FlagListInProject);
}
/*! /*!
The project that owns and manages the node. It is the first project in the list The project that owns and manages the node. It is the first project in the list
of ancestors. of ancestors.
@@ -209,12 +233,20 @@ QString Node::tooltip() const
bool Node::isEnabled() const bool Node::isEnabled() const
{ {
if (!m_isEnabled) if (!m_flags.testFlag(FlagIsEnabled))
return false; return false;
FolderNode *parent = parentFolderNode(); FolderNode *parent = parentFolderNode();
return parent ? parent->isEnabled() : true; return parent ? parent->isEnabled() : true;
} }
/*!
Returns \c true if the file is automatically generated by a compile step.
*/
bool Node::isGenerated() const
{
return (m_flags & FlagIsGenerated) == FlagIsGenerated;
}
bool Node::supportsAction(ProjectAction, Node *) const bool Node::supportsAction(ProjectAction, Node *) const
{ {
return false; return false;
@@ -222,9 +254,10 @@ bool Node::supportsAction(ProjectAction, Node *) const
void Node::setEnabled(bool enabled) void Node::setEnabled(bool enabled)
{ {
if (m_isEnabled == enabled) if (enabled)
return; m_flags |= FlagIsEnabled;
m_isEnabled = enabled; else
m_flags &= ~FlagIsEnabled;
} }
bool Node::sortByPath(const Node *a, const Node *b) bool Node::sortByPath(const Node *a, const Node *b)
@@ -278,28 +311,30 @@ FileType Node::fileTypeForFileName(const Utils::FileName &file)
FileNode::FileNode(const Utils::FileName &filePath, FileNode::FileNode(const Utils::FileName &filePath,
const FileType fileType, const FileType fileType,
bool generated, int line) : Node(NodeType::File, filePath, line), bool generated, int line) : Node(NodeType::File, filePath, line),
m_fileType(fileType), m_fileType(fileType)
m_generated(generated)
{ {
setListInProject(true);
setIsGenerated(generated);
if (fileType == FileType::Project) if (fileType == FileType::Project)
setPriority(DefaultProjectFilePriority); setPriority(DefaultProjectFilePriority);
else else
setPriority(DefaultFilePriority); setPriority(DefaultFilePriority);
} }
FileNode *FileNode::clone() const
{
auto fn = new FileNode(filePath(), fileType(), isGenerated(), line());
fn->setEnabled(isEnabled());
fn->setPriority(priority());
fn->setListInProject(listInProject());
return fn;
}
FileType FileNode::fileType() const FileType FileNode::fileType() const
{ {
return m_fileType; return m_fileType;
} }
/*!
Returns \c true if the file is automatically generated by a compile step.
*/
bool FileNode::isGenerated() const
{
return m_generated;
}
static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &directory, static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &)> factory, const std::function<FileNode *(const Utils::FileName &)> factory,
QSet<QString> &visited, QFutureInterface<QList<FileNode*>> *future, QSet<QString> &visited, QFutureInterface<QList<FileNode*>> *future,
@@ -379,6 +414,8 @@ FolderNode::FolderNode(const Utils::FileName &folderPath, NodeType nodeType, con
m_displayName(displayName) m_displayName(displayName)
{ {
setPriority(DefaultFolderPriority); setPriority(DefaultFolderPriority);
setListInProject(false);
setIsGenerated(false);
if (m_displayName.isEmpty()) if (m_displayName.isEmpty())
m_displayName = folderPath.toUserOutput(); m_displayName = folderPath.toUserOutput();
} }
@@ -470,7 +507,7 @@ void FolderNode::forEachGenericNode(const std::function<void(Node *)> &genericTa
for (Node *n : m_nodes) { for (Node *n : m_nodes) {
genericTask(n); genericTask(n);
if (FolderNode *fn = n->asFolderNode()) if (FolderNode *fn = n->asFolderNode())
fn->forEachNode(genericTask); fn->forEachGenericNode(genericTask);
} }
} }
@@ -593,7 +630,8 @@ void FolderNode::setIcon(const QIcon &icon)
QString FolderNode::addFileFilter() const QString FolderNode::addFileFilter() const
{ {
return parentFolderNode()->addFileFilter(); FolderNode *fn = parentFolderNode();
return fn ? fn->addFileFilter() : QString();
} }
bool FolderNode::supportsAction(ProjectAction action, Node *node) const bool FolderNode::supportsAction(ProjectAction action, Node *node) const
@@ -718,6 +756,7 @@ ProjectNode::ProjectNode(const Utils::FileName &projectFilePath) :
FolderNode(projectFilePath, NodeType::Project) FolderNode(projectFilePath, NodeType::Project)
{ {
setPriority(DefaultProjectPriority); setPriority(DefaultProjectPriority);
setListInProject(true);
setDisplayName(projectFilePath.fileName()); setDisplayName(projectFilePath.fileName());
} }

View File

@@ -129,6 +129,8 @@ public:
virtual QString displayName() const; virtual QString displayName() const;
virtual QString tooltip() const; virtual QString tooltip() const;
bool isEnabled() const; bool isEnabled() const;
bool listInProject() const;
bool isGenerated() const;
virtual bool supportsAction(ProjectAction action, Node *node) const; virtual bool supportsAction(ProjectAction action, Node *node) const;
@@ -147,6 +149,8 @@ public:
static bool sortByPath(const Node *a, const Node *b); static bool sortByPath(const Node *a, const Node *b);
void setParentFolderNode(FolderNode *parentFolder); void setParentFolderNode(FolderNode *parentFolder);
void setListInProject(bool l);
static FileType fileTypeForMimeType(const Utils::MimeType &mt); static FileType fileTypeForMimeType(const Utils::MimeType &mt);
static FileType fileTypeForFileName(const Utils::FileName &file); static FileType fileTypeForFileName(const Utils::FileName &file);
@@ -154,6 +158,7 @@ protected:
Node(NodeType nodeType, const Utils::FileName &filePath, int line = -1); Node(NodeType nodeType, const Utils::FileName &filePath, int line = -1);
void setPriority(int priority); void setPriority(int priority);
void setIsGenerated(bool g);
private: private:
FolderNode *m_parentFolderNode = nullptr; FolderNode *m_parentFolderNode = nullptr;
@@ -161,17 +166,24 @@ private:
int m_line = -1; int m_line = -1;
int m_priority = DefaultPriority; int m_priority = DefaultPriority;
const NodeType m_nodeType; const NodeType m_nodeType;
bool m_isEnabled = true; enum NodeFlag : quint16 {
FlagNone = 0,
FlagIsEnabled = 1 << 0,
FlagIsGenerated = 1 << 1,
FlagListInProject = 1 << 2,
};
using NodeFlags = QFlags<NodeFlag>;
NodeFlags m_flags = FlagIsEnabled;
}; };
class PROJECTEXPLORER_EXPORT FileNode : public Node class PROJECTEXPLORER_EXPORT FileNode : public Node
{ {
public: public:
FileNode(const Utils::FileName &filePath, const FileType fileType, bool generated, int line = -1); FileNode(const Utils::FileName &filePath, const FileType fileType, bool generated, int line = -1);
FileNode(const FileNode &other) : FileNode(other.filePath(), other.fileType(), true) {}
FileNode *clone() const;
FileType fileType() const; FileType fileType() const;
bool isGenerated() const;
FileNode *asFileNode() final { return this; } FileNode *asFileNode() final { return this; }
const FileNode *asFileNode() const final { return this; } const FileNode *asFileNode() const final { return this; }
@@ -183,7 +195,6 @@ public:
private: private:
FileType m_fileType; FileType m_fileType;
bool m_generated;
}; };
// Documentation inside. // Documentation inside.

View File

@@ -59,9 +59,23 @@ void setupArtifacts(ProjectExplorer::FolderNode *root, const QList<qbs::Artifact
const Utils::FileName path = Utils::FileName::fromString(ad.filePath()); const Utils::FileName path = Utils::FileName::fromString(ad.filePath());
const ProjectExplorer::FileType type = fileType(ad); const ProjectExplorer::FileType type = fileType(ad);
const bool isGenerated = ad.isGenerated(); const bool isGenerated = ad.isGenerated();
root->addNestedNode(new ProjectExplorer::FileNode(path, type, isGenerated));
};
// A list of human-readable file types that we can reasonably expect
// to get generated during a build. Extend as needed.
static const QSet<QString> sourceTags = {
QLatin1String("c"), QLatin1String("cpp"), QLatin1String("hpp"),
QLatin1String("objc"), QLatin1String("objcpp"),
QLatin1String("c_pch_src"), QLatin1String("cpp_pch_src"),
QLatin1String("objc_pch_src"), QLatin1String("objcpp_pch_src"),
QLatin1String("asm"), QLatin1String("asm_cpp"),
QLatin1String("linkerscript"),
QLatin1String("qrc"), QLatin1String("java.java")
};
ProjectExplorer::FileNode * const node
= new ProjectExplorer::FileNode(path, type, isGenerated);
node->setListInProject(!isGenerated || ad.fileTags().toSet().intersects(sourceTags));
root->addNestedNode(node);
}
root->compress(); root->compress();
} }

View File

@@ -29,6 +29,9 @@
#include <coreplugin/fileiconprovider.h> #include <coreplugin/fileiconprovider.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <resourceeditor/resourcenode.h> #include <resourceeditor/resourcenode.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -39,6 +42,7 @@
using namespace Core; using namespace Core;
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace QtSupport;
using namespace Utils; using namespace Utils;
namespace { namespace {
@@ -135,7 +139,7 @@ void clearQmakeStaticData()
namespace QmakeProjectManager { namespace QmakeProjectManager {
static void createTree(const QmakePriFile *pri, QmakePriFileNode *node) static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const FileNameList &toExclude)
{ {
QTC_ASSERT(pri, return); QTC_ASSERT(pri, return);
QTC_ASSERT(node, return); QTC_ASSERT(node, return);
@@ -150,7 +154,9 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node)
const QVector<QmakeStaticData::FileTypeData> &fileTypes = qmakeStaticData()->fileTypeData; const QVector<QmakeStaticData::FileTypeData> &fileTypes = qmakeStaticData()->fileTypeData;
for (int i = 0; i < fileTypes.size(); ++i) { for (int i = 0; i < fileTypes.size(); ++i) {
FileType type = fileTypes.at(i).type; FileType type = fileTypes.at(i).type;
const QSet<FileName> &newFilePaths = pri->files(type); const QSet<FileName> &newFilePaths = Utils::filtered(pri->files(type), [&toExclude](const Utils::FileName &fn) {
return !Utils::contains(toExclude, [&fn](const Utils::FileName &ex) { return fn.isChildOf(ex); });
});
if (!newFilePaths.isEmpty()) { if (!newFilePaths.isEmpty()) {
auto vfolder = new VirtualFolderNode(pri->filePath().parentDir(), Node::DefaultVirtualFolderPriority - i); auto vfolder = new VirtualFolderNode(pri->filePath().parentDir(), Node::DefaultVirtualFolderPriority - i);
@@ -162,13 +168,14 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node)
for (const FileName &file : newFilePaths) { for (const FileName &file : newFilePaths) {
auto vfs = pri->project()->qmakeVfs(); auto vfs = pri->project()->qmakeVfs();
QString contents; QString contents;
QString errorMessage;
// Prefer the cumulative file if it's non-empty, based on the assumption // Prefer the cumulative file if it's non-empty, based on the assumption
// that it contains more "stuff". // that it contains more "stuff".
vfs->readVirtualFile(file.toString(), QMakeVfs::VfsCumulative, &contents); vfs->readFile(file.toString(), QMakeVfs::VfsCumulative, &contents, &errorMessage);
// If the cumulative evaluation botched the file too much, try the exact one. // If the cumulative evaluation botched the file too much, try the exact one.
if (contents.isEmpty()) if (contents.isEmpty())
vfs->readVirtualFile(file.toString(), QMakeVfs::VfsExact, &contents); vfs->readFile(file.toString(), QMakeVfs::VfsExact, &contents, &errorMessage);
auto resourceNode = new ResourceEditor::ResourceTopLevelNode(file, contents, vfolder); auto resourceNode = new ResourceEditor::ResourceTopLevelNode(file, false, contents, vfolder);
vfolder->addNode(resourceNode); vfolder->addNode(resourceNode);
} }
} else { } else {
@@ -188,15 +195,22 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node)
newNode = new QmakeProFileNode(c->project(), c->filePath()); newNode = new QmakeProFileNode(c->project(), c->filePath());
else else
newNode = new QmakePriFileNode(c->project(), node->proFileNode(), c->filePath()); newNode = new QmakePriFileNode(c->project(), node->proFileNode(), c->filePath());
createTree(c, newNode); createTree(c, newNode, toExclude);
node->addNode(newNode); node->addNode(newNode);
} }
} }
QmakeProFileNode *QmakeNodeTreeBuilder::buildTree(QmakeProject *project) QmakeProFileNode *QmakeNodeTreeBuilder::buildTree(QmakeProject *project)
{ {
// Remove qmake implementation details that litter up the project data:
Target *t = project->activeTarget();
Kit *k = t ? t->kit() : nullptr;
BaseQtVersion *qt = k ? QtKitInformation::qtVersion(k) : nullptr;
const FileNameList toExclude = qt ? qt->directoriesToIgnoreInProjectTree() : FileNameList();
auto root = new QmakeProFileNode(project, project->projectFilePath()); auto root = new QmakeProFileNode(project, project->projectFilePath());
createTree(project->rootProFile(), root); createTree(project->rootProFile(), root, toExclude);
return root; return root;
} }

View File

@@ -358,14 +358,15 @@ void QmakeProject::updateQmlJSCodeModel()
projectInfo.activeResourceFiles.append(exactResources); projectInfo.activeResourceFiles.append(exactResources);
projectInfo.allResourceFiles.append(exactResources); projectInfo.allResourceFiles.append(exactResources);
projectInfo.allResourceFiles.append(cumulativeResources); projectInfo.allResourceFiles.append(cumulativeResources);
QString errorMessage;
foreach (const QString &rc, exactResources) { foreach (const QString &rc, exactResources) {
QString contents; QString contents;
if (m_qmakeVfs->readVirtualFile(rc, QMakeVfs::VfsExact, &contents)) if (m_qmakeVfs->readFile(rc, QMakeVfs::VfsExact, &contents, &errorMessage) == QMakeVfs::ReadOk)
projectInfo.resourceFileContents[rc] = contents; projectInfo.resourceFileContents[rc] = contents;
} }
foreach (const QString &rc, cumulativeResources) { foreach (const QString &rc, cumulativeResources) {
QString contents; QString contents;
if (m_qmakeVfs->readVirtualFile(rc, QMakeVfs::VfsCumulative, &contents)) if (m_qmakeVfs->readFile(rc, QMakeVfs::VfsCumulative, &contents, &errorMessage) == QMakeVfs::ReadOk)
projectInfo.resourceFileContents[rc] = contents; projectInfo.resourceFileContents[rc] = contents;
} }
if (!hasQmlLib) { if (!hasQmlLib) {

View File

@@ -55,6 +55,21 @@ QString AddSignalHandlerDialog::signal() const
return m_signal; return m_signal;
} }
bool checkForPropertyChanges(const QString &signal)
{
static const QStringList importantProperties = {"pressed","position","value",
"checked","currentIndex","index",
"text","currentText", "currentItem"};
if (!signal.endsWith("Changed"))
return true;
QString property = signal;
property.chop(7);
/* Some important property changes we keep */
return importantProperties.contains(property);
}
void AddSignalHandlerDialog::updateComboBox() void AddSignalHandlerDialog::updateComboBox()
{ {
m_ui->comboBox->clear(); m_ui->comboBox->clear();
@@ -62,14 +77,12 @@ void AddSignalHandlerDialog::updateComboBox()
if (m_ui->all->isChecked()) { if (m_ui->all->isChecked()) {
m_ui->comboBox->addItem(signal); m_ui->comboBox->addItem(signal);
} else if (m_ui->properties->isChecked()) { } else if (m_ui->properties->isChecked()) {
if (signal.contains(QLatin1String("Changed"))) if (signal.endsWith("Changed"))
m_ui->comboBox->addItem(signal); m_ui->comboBox->addItem(signal);
} else { } else if (checkForPropertyChanges(signal))
if (!signal.contains(QLatin1String("Changed")))
m_ui->comboBox->addItem(signal); m_ui->comboBox->addItem(signal);
} }
} }
}
void AddSignalHandlerDialog::handleAccepted() void AddSignalHandlerDialog::handleAccepted()
{ {

View File

@@ -840,8 +840,13 @@ void addItemToStackedContainer(const SelectionContext &selectionContext)
RewriterTransaction transaction = RewriterTransaction transaction =
view->beginRewriterTransaction(QByteArrayLiteral("DesignerActionManager:addItemToStackedContainer")); view->beginRewriterTransaction(QByteArrayLiteral("DesignerActionManager:addItemToStackedContainer"));
NodeMetaInfo itemMetaInfo = view->model()->metaInfo("QtQuick.Item", -1, -1);
QTC_ASSERT(itemMetaInfo.isValid(), return);
QTC_ASSERT(itemMetaInfo.majorVersion() == 2, return);
QmlDesigner::ModelNode itemNode = QmlDesigner::ModelNode itemNode =
view->createModelNode("QtQuick.Item", view->majorQtQuickVersion(), view->minorQtQuickVersion()); view->createModelNode("QtQuick.Item", itemMetaInfo.majorVersion(), itemMetaInfo.minorVersion());
container.defaultNodeListProperty().reparentHere(itemNode); container.defaultNodeListProperty().reparentHere(itemNode);
if (potentialTabBar.isValid()) {// The stacked container is hooked up to a TabBar if (potentialTabBar.isValid()) {// The stacked container is hooked up to a TabBar

View File

@@ -46,10 +46,17 @@ TextEditItemWidget::~TextEditItemWidget()
setWidget(0); setWidget(0);
} }
void TextEditItemWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) void TextEditItemWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{ {
painter->fillRect(boundingRect(), Qt::white); painter->fillRect(boundingRect(), Qt::white);
QGraphicsProxyWidget::paint(painter, option, widget);
/* Cursor painting is broken.
* QGraphicsProxyWidget::paint(painter, option, widget);
* We draw manually instead.
*/
QPixmap pixmap = widget()->grab();
painter->drawPixmap(0, 0, pixmap);
} }
QLineEdit* TextEditItemWidget::lineEdit() const QLineEdit* TextEditItemWidget::lineEdit() const

View File

@@ -84,10 +84,13 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
Constants::QMLTYPES_MIMETYPE, Constants::QMLTYPES_MIMETYPE,
Constants::QMLUI_MIMETYPE }; Constants::QMLUI_MIMETYPE };
projectInfo.sourceFiles = project->files(Project::SourceFiles, projectInfo.sourceFiles = project->files(Project::SourceFiles,
[&qmlTypeNames](const FileNode *fn) { [&qmlTypeNames](const Node *n) {
if (const FileNode *fn = n->asFileNode()) {
return fn->fileType() == FileType::QML return fn->fileType() == FileType::QML
&& qmlTypeNames.contains(Utils::mimeTypeForFile(fn->filePath().toString(), && qmlTypeNames.contains(Utils::mimeTypeForFile(fn->filePath().toString(),
MimeMatchMode::MatchExtension).name()); MimeMatchMode::MatchExtension).name());
}
return false;
}); });
activeTarget = project->activeTarget(); activeTarget = project->activeTarget();
} }

View File

@@ -570,6 +570,22 @@ FileName BaseQtVersion::mkspecsPath() const
return result; return result;
} }
FileNameList BaseQtVersion::directoriesToIgnoreInProjectTree() const
{
FileNameList result;
const FileName mkspecPathGet = mkspecsPath();
result.append(mkspecPathGet);
FileName mkspecPathSrc = FileName::fromUserInput(qmakeProperty("QT_HOST_DATA", PropertyVariantSrc));
if (!mkspecPathSrc.isEmpty()) {
mkspecPathSrc.appendPath("mkspecs");
if (mkspecPathSrc != mkspecPathGet)
result.append(mkspecPathSrc);
}
return result;
}
QString BaseQtVersion::qtNamespace() const QString BaseQtVersion::qtNamespace() const
{ {
ensureMkSpecParsed(); ensureMkSpecParsed();

View File

@@ -212,6 +212,8 @@ public:
Utils::FileName binPath() const; Utils::FileName binPath() const;
Utils::FileName mkspecsPath() const; Utils::FileName mkspecsPath() const;
Utils::FileNameList directoriesToIgnoreInProjectTree() const;
QString qtNamespace() const; QString qtNamespace() const;
QString qtLibInfix() const; QString qtLibInfix() const;
bool isFrameworkBuild() const; bool isFrameworkBuild() const;

View File

@@ -222,7 +222,8 @@ void ResourceEditorPlugin::extensionsInitialized()
FolderNode *const pn = file->parentFolderNode(); FolderNode *const pn = file->parentFolderNode();
QTC_ASSERT(pn, continue); QTC_ASSERT(pn, continue);
const Utils::FileName path = file->filePath(); const Utils::FileName path = file->filePath();
pn->replaceSubtree(file, new ResourceTopLevelNode(path, QString(), pn)); pn->replaceSubtree(file, new ResourceTopLevelNode(path, file->isGenerated(),
QString(), pn));
} }
}); });
} }

View File

@@ -70,7 +70,7 @@ public:
{ {
if (type == TypePermissions) if (type == TypePermissions)
return true; return true;
auto newNode = new ResourceTopLevelNode(m_node->filePath(), m_node->contents(), auto newNode = new ResourceTopLevelNode(m_node->filePath(), false, m_node->contents(),
m_node->parentFolderNode()); m_node->parentFolderNode());
m_node->parentFolderNode()->replaceSubtree(m_node, newNode); m_node->parentFolderNode()->replaceSubtree(m_node, newNode);
return true; return true;
@@ -263,10 +263,11 @@ bool SimpleResourceFolderNode::renameFile(const QString &filePath, const QString
} // Internal } // Internal
ResourceTopLevelNode::ResourceTopLevelNode(const FileName &filePath, const QString &contents, ResourceTopLevelNode::ResourceTopLevelNode(const FileName &filePath, bool generated,
FolderNode *parent) const QString &contents, FolderNode *parent)
: FolderNode(filePath) : FolderNode(filePath)
{ {
setIsGenerated(generated);
setIcon(FileIconProvider::icon(filePath.toString())); setIcon(FileIconProvider::icon(filePath.toString()));
if (contents.isEmpty()) { if (contents.isEmpty()) {
m_document = new ResourceFileWatcher(this); m_document = new ResourceFileWatcher(this);

View File

@@ -34,7 +34,8 @@ namespace Internal { class ResourceFileWatcher; }
class RESOURCE_EXPORT ResourceTopLevelNode : public ProjectExplorer::FolderNode class RESOURCE_EXPORT ResourceTopLevelNode : public ProjectExplorer::FolderNode
{ {
public: public:
ResourceTopLevelNode(const Utils::FileName &filePath, const QString &contents, FolderNode *parent); ResourceTopLevelNode(const Utils::FileName &filePath, bool generated,
const QString &contents, FolderNode *parent);
~ResourceTopLevelNode() override; ~ResourceTopLevelNode() override;
void addInternalNodes(); void addInternalNodes();

View File

@@ -45,6 +45,7 @@ namespace {
static const QLatin1String kPop("#pop"); static const QLatin1String kPop("#pop");
static const QLatin1Char kBackSlash('\\'); static const QLatin1Char kBackSlash('\\');
static const QLatin1Char kHash('#'); static const QLatin1Char kHash('#');
static const QLatin1Char kExclamationMark('!');
} }
class HighlighterCodeFormatterData : public CodeFormatterData class HighlighterCodeFormatterData : public CodeFormatterData
@@ -414,8 +415,13 @@ void Highlighter::changeContext(const QString &contextName,
const QSharedPointer<HighlightDefinition> &definition, const QSharedPointer<HighlightDefinition> &definition,
const bool assignCurrent) const bool assignCurrent)
{ {
if (contextName.startsWith(kPop)) { QString identifier = contextName;
const int count = contextName.splitRef(kHash, QString::SkipEmptyParts).size(); if (identifier.startsWith(kPop)) {
const QStringList complexOrder = contextName.split(kExclamationMark);
const QString orders = complexOrder.first();
identifier = complexOrder.size() > 1 ? complexOrder[1] : QString();
const int count = orders.splitRef(kHash, QString::SkipEmptyParts).size();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
if (m_contexts.isEmpty()) { if (m_contexts.isEmpty()) {
throw HighlighterException( throw HighlighterException(
@@ -434,8 +440,9 @@ void Highlighter::changeContext(const QString &contextName,
setCurrentBlockState( setCurrentBlockState(
computeState(m_leadingObservableStates.value(currentSequence))); computeState(m_leadingObservableStates.value(currentSequence)));
} }
} else { }
const QSharedPointer<Context> &context = definition->context(contextName); if (!identifier.isEmpty()) {
const QSharedPointer<Context> &context = definition->context(identifier);
if (context->isDynamic()) if (context->isDynamic())
pushDynamicContext(context); pushDynamicContext(context);

View File

@@ -25,7 +25,9 @@
#include "outputprocessor.h" #include "outputprocessor.h"
#include <QCoreApplication> #include <utils/theme/theme_p.h>
#include <QGuiApplication>
#include <QFile> #include <QFile>
#include <QMetaObject> #include <QMetaObject>
#include <QFileInfo> #include <QFileInfo>
@@ -35,6 +37,17 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
class DummyTheme : public Utils::Theme
{
public:
DummyTheme() : Utils::Theme(QLatin1String("dummy"))
{
const QPair<QColor, QString> colorEntry(QColor(Qt::red), QLatin1String("red"));
for (int i = 0; i < d->colors.count(); ++i)
d->colors[i] = colorEntry;
}
};
static void printUsage() static void printUsage()
{ {
fprintf(stderr, "Usage: %s [--type <compiler type>] <file>\n", fprintf(stderr, "Usage: %s [--type <compiler type>] <file>\n",
@@ -48,10 +61,11 @@ static void printUsage()
); );
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication app(argc, argv); QGuiApplication app(argc, argv);
DummyTheme dummyTheme;
Utils::setCreatorTheme(&dummyTheme);
QStringList args = app.arguments().mid(1); QStringList args = app.arguments().mid(1);
QString filePath; QString filePath;

View File

@@ -172,7 +172,7 @@ public:
void stopRelayServers(int errorCode = 0); void stopRelayServers(int errorCode = 0);
void writeMaybeBin(const QString &extraMsg, const char *msg, quintptr len); void writeMaybeBin(const QString &extraMsg, const char *msg, quintptr len);
void errorMsg(const QString &msg); void errorMsg(const QString &msg);
void stopGdbRunner(); Q_INVOKABLE void stopGdbRunner();
private: private:
void stopGdbRunner2(); void stopGdbRunner2();
void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress, void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress,

View File

@@ -6748,6 +6748,32 @@ void tst_Dumpers::dumper_data()
+ Check("tc.3.bar", "15", "int"); + Check("tc.3.bar", "15", "int");
QTest::newRow("BufArray")
<< Data("#include <new>\n"
"static int c = 0;\n"
"struct Foo { int bar = c++; int baz = c++; };\n"
"template<class T>\n"
"struct QtcDumperTest_BufArray {\n"
" const int objSize = int(sizeof(T));\n"
" const int count = 10;\n"
" char *buffer;\n"
" QtcDumperTest_BufArray() {\n"
" buffer = new char[count * objSize];\n"
" for (int i = 0; i < count; ++i)\n"
" new(buffer + i * objSize) T;\n"
" }\n"
" ~QtcDumperTest_BufArray() { delete[] buffer; }\n"
"};\n\n",
"QtcDumperTest_BufArray<Foo> arr; unused(&arr);\n")
+ Cxx11Profile()
+ Check("arr.0.bar", "0", "int")
+ Check("arr.0.baz", "1", "int")
+ Check("arr.1.bar", "2", "int")
+ Check("arr.1.baz", "3", "int")
+ Check("arr.2.bar", "4", "int")
+ Check("arr.2.baz", "5", "int");
QTest::newRow("UndefinedStaticMembers") QTest::newRow("UndefinedStaticMembers")
<< Data("struct Foo { int a = 15; static int b; }; \n", << Data("struct Foo { int a = 15; static int b; }; \n",
"Foo f; unused(&f);\n") "Foo f; unused(&f);\n")

View File

@@ -33,7 +33,7 @@ def verifyCloneLog(targetDir, canceled):
summary = "Failed." summary = "Failed."
else: else:
finish = findObject(":Git Repository Clone.Finish_QPushButton") finish = findObject(":Git Repository Clone.Finish_QPushButton")
waitFor("finish.enabled", 30000) waitFor("finish.enabled", 90000)
cloneLog = str(waitForObject(":Git Repository Clone.logPlainTextEdit_QPlainTextEdit").plainText) cloneLog = str(waitForObject(":Git Repository Clone.logPlainTextEdit_QPlainTextEdit").plainText)
if "fatal: " in cloneLog: if "fatal: " in cloneLog:
test.warning("Cloning failed outside Creator.") test.warning("Cloning failed outside Creator.")

View File

@@ -145,9 +145,9 @@ def verifyClickCommit():
"Verifying whether diff editor contains pointless_header.h file.") "Verifying whether diff editor contains pointless_header.h file.")
test.verify(pointlessHeader not in diffOriginal, test.verify(pointlessHeader not in diffOriginal,
"Verifying whether original does not contain pointless_header.h file.") "Verifying whether original does not contain pointless_header.h file.")
test.verify("HEADERS += mainwindow.h \\\n pointless_header.h\n" in diffChanged, test.verify("HEADERS += \\\n mainwindow.h \\\n pointless_header.h\n" in diffChanged,
"Verifying whether diff editor has pointless_header.h listed in pro file.") "Verifying whether diff editor has pointless_header.h listed in pro file.")
test.verify("HEADERS += mainwindow.h\n\n" in diffOriginal test.verify("HEADERS += \\\n mainwindow.h\n\n" in diffOriginal
and "pointless_header.h" not in diffOriginal, and "pointless_header.h" not in diffOriginal,
"Verifying whether original has no additional header in pro file.") "Verifying whether original has no additional header in pro file.")
test.verify(original.readOnly and changed.readOnly, test.verify(original.readOnly and changed.readOnly,