Merge remote-tracking branch 'origin/4.1'

Change-Id: Ieaddc6093d10c08a54acb9b57cbbfe022bc3c038
This commit is contained in:
Orgad Shaneh
2016-09-22 11:01:16 +03:00
21 changed files with 1969 additions and 887 deletions

View File

@@ -46,9 +46,22 @@
\section1 Configuring Devices \section1 Configuring Devices
The process of configuring devices and the UI varies slightly depending on The connections between \QC and an iOS device are protected by using a
the Xcode version that you use. The instructions in this section describe certificate that you receive from Apple when you
the process and UI when using Xcode version 4.6.3. \l{https://developer.apple.com/programs/enroll/}
{enroll in the Apple Developer Program}. The certificate is copied to
the device when you configure the device.
The first time you connect the device to the Mac, you are asked to enable
developer mode on the device. The next time you connect the device, \QC
detects it automatically. To disable automatic connections to a device that
you do not use for development, select \uicontrol Preferences >
\uicontrol iOS, and deselect the \uicontrol {Ask about devices not in
developer mode} check box.
\note The process of configuring devices and the UI varies slightly
depending on the Xcode version that you use. We recommend that you use the
latest available Xcode version.
To configure connections between \QC and an iOS device: To configure connections between \QC and an iOS device:
@@ -58,43 +71,11 @@
\li Connect the device to the Mac computer with a USB cable. \li Connect the device to the Mac computer with a USB cable.
\li Start Xcode to configure the device: \li Start Xcode to configure the device.
\list 1 For example, in Xcode version 7.3.0, select \uicontrol Window >
\uicontrol Device > \uicontrol + > \uicontrol {Add Device} to add
\li Select \uicontrol Window > \uicontrol Organizer. the connected device.
\li Select the \uicontrol + button to add the connected device.
\li Select the device you want to add in the list of devices.
\li If you do not have an Apple developer account, you can now
create one, for a charge.
\li When your account is ready, you can add the device. Your
Apple developer certificate is copied to the device.
\li The first time you connect the device, you are asked to
enable developer mode on the device.
\endlist
The connections between \QC and an iOS device are protected by using an
iOS Developer Program certificate that you receive from Apple for a
charge when you
\l{http://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/EnrollingADP/EnrollingADP.html}
{enroll in the iOS Developer Program}. The certificate is copied to the
device when you configure the device.
The next time you connect the device to the Mac computer, \QC
detects it automatically. To disable automatic connections to a
device that you do not use for development, select \uicontrol Preferences >
\uicontrol iOS, and deselect the
\uicontrol {Ask about devices not in developer mode} check box.
\note If \QC does not detect the devices, the iOS plugin might not be
enabled. Select \uicontrol {Qt Creator} > \uicontrol {About Plugins} >
\uicontrol {Device Support} > \uicontrol iOS and restart \QC.
\li To specify build settings: \li To specify build settings:
@@ -103,8 +84,9 @@
\li Open a project for an application you want to develop for the \li Open a project for an application you want to develop for the
device. device.
\li Select \uicontrol Projects > \uicontrol {Build & Run} > \uicontrol {Add Kit} to \li Select \uicontrol Projects > \uicontrol {Build & Run} >
add a kit for building and running applications on iOS. \uicontrol {Add Kit} to add a kit for building and running
applications on iOS.
\image qtcreator-ios-add-kit.png "Build & Run Settings" \image qtcreator-ios-add-kit.png "Build & Run Settings"
@@ -123,9 +105,10 @@
\endlist \endlist
\note If you cannot deploy applications, because a provisioning profile is \note If you cannot deploy applications, because a provisioning profile is
missing, try refreshing the list of provisioning profiles in Xcode. Select missing, check that provisioning profiles are listed in Xcode by selecting
\uicontrol Xcode > \uicontrol Preferences > \uicontrol Accounts > \uicontrol {View Details}, and \uicontrol Xcode > \uicontrol Preferences > \uicontrol Accounts >
then select the \uicontrol Refresh button. \uicontrol {View Details}. For more information about how to acquire and
install a provisioning profile, see Apple documentation.
\section1 Viewing Device Connection Status \section1 Viewing Device Connection Status

View File

@@ -724,7 +724,12 @@ class Dumper(DumperBase):
self.report('pid="%s"' % self.process.GetProcessID()) self.report('pid="%s"' % self.process.GetProcessID())
# Even if it stops it seems that LLDB assumes it is running # Even if it stops it seems that LLDB assumes it is running
# and later detects that it did stop after all, so it is be # and later detects that it did stop after all, so it is be
# better to mirror that and wait for the spontaneous stop. # better to mirror that and wait for the spontaneous stop
if self.process and self.process.GetState() == lldb.eStateStopped:
# lldb stops the process after attaching. This happens before the
# eventloop starts. Relay the correct state back.
self.reportState("enginerunandinferiorstopok")
else:
self.reportState("enginerunandinferiorrunok") self.reportState("enginerunandinferiorrunok")
elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess: elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess:
self.process = self.target.ConnectRemote( self.process = self.target.ConnectRemote(

File diff suppressed because it is too large Load Diff

View File

@@ -231,7 +231,7 @@ void DebuggerItemManager::autoDetectGdbOrLldbDebuggers()
= lldbInfo.runBlocking(QLatin1String("xcrun"), QStringList() << QLatin1String("--find") = lldbInfo.runBlocking(QLatin1String("xcrun"), QStringList() << QLatin1String("--find")
<< QLatin1String("lldb")); << QLatin1String("lldb"));
if (response.result == Utils::SynchronousProcessResponse::Finished) { if (response.result == Utils::SynchronousProcessResponse::Finished) {
QString lPath = response.allOutput(); QString lPath = response.allOutput().trimmed();
if (!lPath.isEmpty()) { if (!lPath.isEmpty()) {
const QFileInfo fi(lPath); const QFileInfo fi(lPath);
if (fi.exists() && fi.isExecutable() && !fi.isDir()) if (fi.exists() && fi.isExecutable() && !fi.isDir())

View File

@@ -940,9 +940,10 @@ void LldbEngine::handleStateNotification(const GdbMi &reportedState)
if (runParameters().continueAfterAttach) if (runParameters().continueAfterAttach)
m_continueAtNextSpontaneousStop = true; m_continueAtNextSpontaneousStop = true;
notifyEngineRunAndInferiorRunOk(); notifyEngineRunAndInferiorRunOk();
} else if (newState == "enginerunandinferiorstopok") } else if (newState == "enginerunandinferiorstopok") {
notifyEngineRunAndInferiorStopOk(); notifyEngineRunAndInferiorStopOk();
else if (newState == "enginerunokandinferiorunrunnable") continueInferior();
} else if (newState == "enginerunokandinferiorunrunnable")
notifyEngineRunOkAndInferiorUnrunnable(); notifyEngineRunOkAndInferiorUnrunnable();
else if (newState == "inferiorshutdownok") else if (newState == "inferiorshutdownok")
notifyInferiorShutdownOk(); notifyInferiorShutdownOk();

View File

@@ -42,29 +42,6 @@ using namespace VcsBase;
namespace Git { namespace Git {
namespace Internal { namespace Internal {
class MergeToolProcess : public QProcess
{
public:
MergeToolProcess(QObject *parent = 0) : QProcess(parent)
{ }
protected:
qint64 readData(char *data, qint64 maxlen) override
{
qint64 res = QProcess::readData(data, maxlen);
if (res > 0)
VcsOutputWindow::append(QString::fromLocal8Bit(data, int(res)));
return res;
}
qint64 writeData(const char *data, qint64 len) override
{
if (len > 0)
VcsOutputWindow::append(QString::fromLocal8Bit(data, int(len)));
return QProcess::writeData(data, len);
}
};
MergeTool::MergeTool(QObject *parent) : QObject(parent) MergeTool::MergeTool(QObject *parent) : QObject(parent)
{ } { }
@@ -77,7 +54,7 @@ bool MergeTool::start(const QString &workingDirectory, const QStringList &files)
{ {
QStringList arguments; QStringList arguments;
arguments << "mergetool" << "-y" << files; arguments << "mergetool" << "-y" << files;
m_process = new MergeToolProcess(this); m_process = new QProcess(this);
m_process->setWorkingDirectory(workingDirectory); m_process->setWorkingDirectory(workingDirectory);
const Utils::FileName binary = GitPlugin::client()->vcsBinary(); const Utils::FileName binary = GitPlugin::client()->vcsBinary();
VcsOutputWindow::appendCommand(workingDirectory, binary, arguments); VcsOutputWindow::appendCommand(workingDirectory, binary, arguments);
@@ -93,16 +70,9 @@ bool MergeTool::start(const QString &workingDirectory, const QStringList &files)
return true; return true;
} }
MergeTool::FileState MergeTool::waitAndReadStatus(QString &extraInfo) MergeTool::FileState MergeTool::parseStatus(const QByteArray &line, QString &extraInfo)
{ {
QByteArray state; QByteArray state = line.trimmed();
for (int i = 0; i < 5; ++i) {
if (m_process->canReadLine()) {
state = m_process->readLine().trimmed();
break;
}
m_process->waitForReadyRead(500);
}
// " {local}: modified file" // " {local}: modified file"
// " {remote}: deleted" // " {remote}: deleted"
if (!state.isEmpty()) { if (!state.isEmpty()) {
@@ -209,8 +179,7 @@ void MergeTool::chooseAction()
key = QVariant('a'); // abort key = QVariant('a'); // abort
ba.append(key.toChar().toLatin1()); ba.append(key.toChar().toLatin1());
ba.append('\n'); ba.append('\n');
m_process->write(ba); write(ba);
m_process->waitForBytesWritten();
} }
void MergeTool::addButton(QMessageBox *msgBox, const QString &text, char key) void MergeTool::addButton(QMessageBox *msgBox, const QString &text, char key)
@@ -223,25 +192,27 @@ void MergeTool::prompt(const QString &title, const QString &question)
if (QMessageBox::question(Core::ICore::dialogParent(), title, question, if (QMessageBox::question(Core::ICore::dialogParent(), title, question,
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) == QMessageBox::Yes) { QMessageBox::No) == QMessageBox::Yes) {
m_process->write("y\n"); write("y\n");
} else { } else {
m_process->write("n\n"); write("n\n");
} }
m_process->waitForBytesWritten();
} }
void MergeTool::readData() void MergeTool::readData()
{ {
while (m_process->bytesAvailable()) { while (m_process->bytesAvailable()) {
QByteArray line = m_process->canReadLine() ? m_process->readLine() : m_process->readAllStandardOutput(); QByteArray line = m_process->canReadLine() ? m_process->readLine() : m_process->readAllStandardOutput();
VcsOutputWindow::append(QString::fromLocal8Bit(line));
// {Normal|Deleted|Submodule|Symbolic link} merge conflict for 'foo.cpp' // {Normal|Deleted|Submodule|Symbolic link} merge conflict for 'foo.cpp'
int index = line.indexOf(" merge conflict for "); int index = line.indexOf(" merge conflict for ");
if (index != -1) { if (index != -1) {
m_mergeType = mergeType(line.left(index)); m_mergeType = mergeType(line.left(index));
int quote = line.indexOf('\''); int quote = line.indexOf('\'');
m_fileName = QString::fromLocal8Bit(line.mid(quote + 1, line.lastIndexOf('\'') - quote - 1)); m_fileName = QString::fromLocal8Bit(line.mid(quote + 1, line.lastIndexOf('\'') - quote - 1));
m_localState = waitAndReadStatus(m_localInfo); } else if (line.startsWith(" {local}")) {
m_remoteState = waitAndReadStatus(m_remoteInfo); m_localState = parseStatus(line, m_localInfo);
} else if (line.startsWith(" {remote}")) {
m_remoteState = parseStatus(line, m_remoteInfo);
chooseAction(); chooseAction();
} else if (line.startsWith("Was the merge successful")) { } else if (line.startsWith("Was the merge successful")) {
prompt(tr("Unchanged File"), tr("Was the merge successful?")); prompt(tr("Unchanged File"), tr("Was the merge successful?"));
@@ -266,5 +237,12 @@ void MergeTool::done()
deleteLater(); deleteLater();
} }
void MergeTool::write(const QByteArray &bytes)
{
m_process->write(bytes);
m_process->waitForBytesWritten();
VcsOutputWindow::append(QString::fromLocal8Bit(bytes));
}
} // namespace Internal } // namespace Internal
} // namespace Git } // namespace Git

View File

@@ -30,12 +30,12 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QMessageBox; class QMessageBox;
class QProcess;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace Git { namespace Git {
namespace Internal { namespace Internal {
class MergeToolProcess;
class GitClient; class GitClient;
class MergeTool : public QObject class MergeTool : public QObject
@@ -67,14 +67,15 @@ private:
void prompt(const QString &title, const QString &question); void prompt(const QString &title, const QString &question);
void readData(); void readData();
void done(); void done();
void write(const QByteArray &bytes);
FileState waitAndReadStatus(QString &extraInfo); FileState parseStatus(const QByteArray &line, QString &extraInfo);
QString mergeTypeName(); QString mergeTypeName();
QString stateName(FileState state, const QString &extraInfo); QString stateName(FileState state, const QString &extraInfo);
void chooseAction(); void chooseAction();
void addButton(QMessageBox *msgBox, const QString &text, char key); void addButton(QMessageBox *msgBox, const QString &text, char key);
MergeToolProcess *m_process = nullptr; QProcess *m_process = nullptr;
MergeType m_mergeType = NormalMerge; MergeType m_mergeType = NormalMerge;
QString m_fileName; QString m_fileName;
FileState m_localState = UnknownState; FileState m_localState = UnknownState;

View File

@@ -143,7 +143,13 @@ RunControl *IosDebugSupport::createDebugRunControl(IosRunConfiguration *runConfi
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT); ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
} }
} }
if (qmlDebug && !cppDebug) {
if (qmlDebug) {
QTcpServer server;
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|| server.listen(QHostAddress::LocalHostIPv6), return 0);
params.qmlServer.host = server.serverAddress().toString();
if (!cppDebug)
params.startMode = AttachToRemoteServer; params.startMode = AttachToRemoteServer;
} }

View File

@@ -116,5 +116,6 @@ QSet<Core::Id> IosQtVersion::availableFeatures() const
QSet<Core::Id> IosQtVersion::targetDeviceTypes() const QSet<Core::Id> IosQtVersion::targetDeviceTypes() const
{ {
return { Constants::IOS_DEVICE_TYPE }; // iOS Qt version supports ios devices as well as simulator.
return { Constants::IOS_DEVICE_TYPE, Constants::IOS_SIMULATOR_TYPE };
} }

View File

@@ -123,7 +123,7 @@ public:
}; };
explicit IosToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q); explicit IosToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q);
virtual ~IosToolHandlerPrivate() {} virtual ~IosToolHandlerPrivate();
virtual void requestTransferApp(const QString &bundlePath, const QString &deviceId, virtual void requestTransferApp(const QString &bundlePath, const QString &deviceId,
int timeout = 1000) = 0; int timeout = 1000) = 0;
virtual void requestRunApp(const QString &bundlePath, const QStringList &extraArgs, virtual void requestRunApp(const QString &bundlePath, const QStringList &extraArgs,
@@ -158,7 +158,7 @@ protected:
void processXml(); void processXml();
IosToolHandler *q; IosToolHandler *q;
QProcess process; QProcess *process;
QTimer killTimer; QTimer killTimer;
QXmlStreamReader outputParser; QXmlStreamReader outputParser;
QString deviceId; QString deviceId;
@@ -202,7 +202,12 @@ private:
IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType, IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType,
Ios::IosToolHandler *q) : Ios::IosToolHandler *q) :
q(q), state(NonStarted), devType(devType), iBegin(0), iEnd(0), q(q),
process(new QProcess),
state(NonStarted),
devType(devType),
iBegin(0),
iEnd(0),
gdbSocket(-1) gdbSocket(-1)
{ {
killTimer.setSingleShot(true); killTimer.setSingleShot(true);
@@ -225,20 +230,30 @@ IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType,
<< QLatin1String("/System/Library/PrivateFrameworks"); << QLatin1String("/System/Library/PrivateFrameworks");
env.insert(QLatin1String("DYLD_FALLBACK_FRAMEWORK_PATH"), frameworkPaths.join(QLatin1Char(':'))); env.insert(QLatin1String("DYLD_FALLBACK_FRAMEWORK_PATH"), frameworkPaths.join(QLatin1Char(':')));
qCDebug(toolHandlerLog) << "IosToolHandler runEnv:" << env.toStringList(); qCDebug(toolHandlerLog) << "IosToolHandler runEnv:" << env.toStringList();
process.setProcessEnvironment(env); process->setProcessEnvironment(env);
QObject::connect(&process, &QProcess::readyReadStandardOutput, QObject::connect(process, &QProcess::readyReadStandardOutput,
q, &IosToolHandler::subprocessHasData); q, &IosToolHandler::subprocessHasData);
QObject::connect(&process, QObject::connect(process,
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
q, &IosToolHandler::subprocessFinished); q, &IosToolHandler::subprocessFinished);
QObject::connect(&process, &QProcess::errorOccurred, q, &IosToolHandler::subprocessError); QObject::connect(process, &QProcess::errorOccurred, q, &IosToolHandler::subprocessError);
QObject::connect(&killTimer, &QTimer::timeout, QObject::connect(&killTimer, &QTimer::timeout,
q, &IosToolHandler::killProcess); q, &IosToolHandler::killProcess);
} }
IosToolHandlerPrivate::~IosToolHandlerPrivate()
{
if (isRunning()) {
process->terminate();
if (!process->waitForFinished(1000))
process->kill();
}
delete process;
}
bool IosToolHandlerPrivate::isRunning() bool IosToolHandlerPrivate::isRunning()
{ {
return process.state() != QProcess::NotRunning; return process && (process->state() != QProcess::NotRunning);
} }
void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args) void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args)
@@ -246,7 +261,7 @@ void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args)
QTC_CHECK(state == NonStarted); QTC_CHECK(state == NonStarted);
state = Starting; state = Starting;
qCDebug(toolHandlerLog) << "running " << exe << args; qCDebug(toolHandlerLog) << "running " << exe << args;
process.start(exe, args); process->start(exe, args);
state = StartedInferior; state = StartedInferior;
} }
@@ -281,9 +296,9 @@ void IosToolHandlerPrivate::stop(int errorCode)
case Stopped: case Stopped:
return; return;
} }
if (process.state() != QProcess::NotRunning) { if (isRunning()) {
process.write("k\n\r"); process->write("k\n\r");
process.closeWriteChannel(); process->closeWriteChannel();
killTimer.start(1500); killTimer.start(1500);
} }
} }
@@ -554,8 +569,8 @@ void IosToolHandlerPrivate::subprocessHasData()
// read some data // read some data
{ {
char buf[200]; char buf[200];
while (true) { while (isRunning()) {
qint64 rRead = process.read(buf, sizeof(buf)); qint64 rRead = process->read(buf, sizeof(buf));
if (rRead == -1) { if (rRead == -1) {
stop(-1); stop(-1);
return; return;
@@ -704,8 +719,8 @@ void IosSimulatorToolHandlerPrivate::addDeviceArguments(QStringList &args) const
void IosToolHandlerPrivate::killProcess() void IosToolHandlerPrivate::killProcess()
{ {
if (process.state() != QProcess::NotRunning) if (isRunning())
process.kill(); process->kill();
} }
} // namespace Internal } // namespace Internal

View File

@@ -56,7 +56,7 @@ public:
Abi targetAbi() const override; Abi targetAbi() const override;
QString originalTargetTriple() const override; QString originalTargetTriple() const override;
QString version() const; QString version() const;
QList<Abi> supportedAbis() const; QList<Abi> supportedAbis() const override;
void setTargetAbi(const Abi &); void setTargetAbi(const Abi &);
bool isValid() const override; bool isValid() const override;

View File

@@ -819,7 +819,7 @@ QVector<int> MiniProjectTargetSelector::listWidgetWidths(int minSize, int maxSiz
} }
widthToDistribute -= delta * i; widthToDistribute -= delta * i;
if (widthToDistribute == 0) if (widthToDistribute <= 0)
return result; return result;
first = result[indexes.first()]; first = result[indexes.first()];

View File

@@ -149,6 +149,11 @@ Core::Id ToolChain::typeId() const
return d->m_typeId; return d->m_typeId;
} }
QList<Abi> ToolChain::supportedAbis() const
{
return { targetAbi() };
}
const QSet<ToolChain::Language> &ToolChain::allLanguages() const QSet<ToolChain::Language> &ToolChain::allLanguages()
{ {
static QSet<Language> languages({ Language::C, Language::Cxx }); static QSet<Language> languages({ Language::C, Language::Cxx });

View File

@@ -81,6 +81,7 @@ public:
Core::Id typeId() const; Core::Id typeId() const;
virtual QString typeDisplayName() const = 0; virtual QString typeDisplayName() const = 0;
virtual Abi targetAbi() const = 0; virtual Abi targetAbi() const = 0;
virtual QList<Abi> supportedAbis() const;
virtual QString originalTargetTriple() const { return QString(); } virtual QString originalTargetTriple() const { return QString(); }
virtual bool isValid() const = 0; virtual bool isValid() const = 0;

View File

@@ -342,8 +342,11 @@ QList<ToolChain *> ToolChainManager::findToolChains(const Abi &abi)
{ {
QList<ToolChain *> result; QList<ToolChain *> result;
foreach (ToolChain *tc, d->m_toolChains) { foreach (ToolChain *tc, d->m_toolChains) {
Abi targetAbi = tc->targetAbi(); bool isCompatible = Utils::anyOf(tc->supportedAbis(), [abi](const Abi &supportedAbi) {
if (targetAbi.isCompatibleWith(abi)) return supportedAbi.isCompatibleWith(abi);
});
if (isCompatible)
result.append(tc); result.append(tc);
} }
return result; return result;

View File

@@ -99,7 +99,7 @@ void DebugMessagesModel::loadEvent(const QmlEvent &event, const QmlEventType &ty
m_data.insert(insert(event.timestamp(), 0, type.detailType()), m_data.insert(insert(event.timestamp(), 0, type.detailType()),
MessageData(event.string(), event.typeIndex())); MessageData(event.string(), event.typeIndex()));
if (type.detailType() > m_maximumMsgType) if (type.detailType() > m_maximumMsgType)
m_maximumMsgType = event.typeIndex(); m_maximumMsgType = type.detailType();
} }
void DebugMessagesModel::finalize() void DebugMessagesModel::finalize()

View File

@@ -44,7 +44,9 @@ FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager,
{ {
m_modelManager = modelManager; m_modelManager = modelManager;
m_callStack.append(QmlEvent()); m_callStack.append(QmlEvent());
m_stackTop = &m_stackBottom; m_compileStack.append(QmlEvent());
m_callStackTop = &m_stackBottom;
m_compileStackTop = &m_stackBottom;
connect(modelManager, &QmlProfilerModelManager::stateChanged, connect(modelManager, &QmlProfilerModelManager::stateChanged,
this, &FlameGraphModel::onModelManagerStateChanged); this, &FlameGraphModel::onModelManagerStateChanged);
connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed, connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed,
@@ -64,8 +66,11 @@ void FlameGraphModel::clear()
beginResetModel(); beginResetModel();
m_stackBottom = FlameGraphData(0, -1, 1); m_stackBottom = FlameGraphData(0, -1, 1);
m_callStack.clear(); m_callStack.clear();
m_compileStack.clear();
m_callStack.append(QmlEvent()); m_callStack.append(QmlEvent());
m_stackTop = &m_stackBottom; m_compileStack.append(QmlEvent());
m_callStackTop = &m_stackBottom;
m_compileStackTop = &m_stackBottom;
m_typeIdsWithNotes.clear(); m_typeIdsWithNotes.clear();
endResetModel(); endResetModel();
} }
@@ -99,7 +104,11 @@ void FlameGraphModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
if (m_stackBottom.children.isEmpty()) if (m_stackBottom.children.isEmpty())
beginResetModel(); beginResetModel();
const QmlEvent *potentialParent = &(m_callStack.top()); const bool isCompiling = (type.rangeType() == Compiling);
QStack<QmlEvent> &stack = isCompiling ? m_compileStack : m_callStack;
FlameGraphData *&stackTop = isCompiling ? m_compileStackTop : m_callStackTop;
const QmlEvent *potentialParent = &(stack.top());
if (type.message() == MemoryAllocation) { if (type.message() == MemoryAllocation) {
if (type.detailType() == HeapPage) if (type.detailType() == HeapPage)
return; // We're only interested in actual allocations, not heap pages being mmap'd return; // We're only interested in actual allocations, not heap pages being mmap'd
@@ -108,20 +117,20 @@ void FlameGraphModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
if (amount < 0) if (amount < 0)
return; // We're not interested in GC runs here return; // We're not interested in GC runs here
for (FlameGraphData *data = m_stackTop; data; data = data->parent) { for (FlameGraphData *data = stackTop; data; data = data->parent) {
++data->allocations; ++data->allocations;
data->memory += amount; data->memory += amount;
} }
} else if (event.rangeStage() == RangeEnd) { } else if (event.rangeStage() == RangeEnd) {
m_stackTop->duration += event.timestamp() - potentialParent->timestamp(); stackTop->duration += event.timestamp() - potentialParent->timestamp();
m_callStack.pop(); stack.pop();
m_stackTop = m_stackTop->parent; stackTop = stackTop->parent;
potentialParent = &(m_callStack.top()); potentialParent = &(stack.top());
} else { } else {
QTC_ASSERT(event.rangeStage() == RangeStart, return); QTC_ASSERT(event.rangeStage() == RangeStart, return);
m_callStack.push(event); stack.push(event);
m_stackTop = pushChild(m_stackTop, event); stackTop = pushChild(stackTop, event);
} }
} }

View File

@@ -101,8 +101,10 @@ private:
// used by binding loop detection // used by binding loop detection
QStack<QmlEvent> m_callStack; QStack<QmlEvent> m_callStack;
QStack<QmlEvent> m_compileStack;
FlameGraphData m_stackBottom; FlameGraphData m_stackBottom;
FlameGraphData *m_stackTop; FlameGraphData *m_callStackTop;
FlameGraphData *m_compileStackTop;
int m_modelId; int m_modelId;
QmlProfilerModelManager *m_modelManager; QmlProfilerModelManager *m_modelManager;

View File

@@ -36,7 +36,7 @@ MemoryUsageModel::MemoryUsageModel(QmlProfilerModelManager *manager, QObject *pa
QmlProfilerTimelineModel(manager, MemoryAllocation, MaximumRangeType, ProfileMemory, parent) QmlProfilerTimelineModel(manager, MemoryAllocation, MaximumRangeType, ProfileMemory, parent)
{ {
// Announce additional features. The base class already announces the main feature. // Announce additional features. The base class already announces the main feature.
announceFeatures(Constants::QML_JS_RANGE_FEATURES); announceFeatures(Constants::QML_JS_RANGE_FEATURES ^ (1 << ProfileCompiling));
} }
int MemoryUsageModel::rowMaxValue(int rowNumber) const int MemoryUsageModel::rowMaxValue(int rowNumber) const
@@ -128,7 +128,8 @@ QVariantMap MemoryUsageModel::details(int index) const
bool MemoryUsageModel::accepted(const QmlEventType &type) const bool MemoryUsageModel::accepted(const QmlEventType &type) const
{ {
return QmlProfilerTimelineModel::accepted(type) || type.rangeType() != MaximumRangeType; return QmlProfilerTimelineModel::accepted(type)
|| (type.rangeType() != MaximumRangeType && type.rangeType() != Compiling);
} }
void MemoryUsageModel::loadEvent(const QmlEvent &event, const QmlEventType &type) void MemoryUsageModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
@@ -258,6 +259,14 @@ void MemoryUsageModel::clear()
QmlProfilerTimelineModel::clear(); QmlProfilerTimelineModel::clear();
} }
bool MemoryUsageModel::handlesTypeId(int typeId) const
{
Q_UNUSED(typeId);
// We don't want the memory ranges allocated by some QML/JS function to be highlighted when
// propagating a typeId selection to the timeline. The actual range should be highlighted.
return false;
}
MemoryUsageModel::MemoryAllocationItem::MemoryAllocationItem(int typeId, qint64 baseAmount) : MemoryUsageModel::MemoryAllocationItem::MemoryAllocationItem(int typeId, qint64 baseAmount) :
size(baseAmount), allocated(0), deallocated(0), allocations(0), deallocations(0), size(baseAmount), allocated(0), deallocated(0), allocations(0), deallocations(0),
typeId(typeId) typeId(typeId)

View File

@@ -71,6 +71,7 @@ public:
void loadEvent(const QmlEvent &event, const QmlEventType &type) override; void loadEvent(const QmlEvent &event, const QmlEventType &type) override;
void finalize() override; void finalize() override;
void clear() override; void clear() override;
bool handlesTypeId(int typeId) const override;
private: private:
struct RangeStackFrame { struct RangeStackFrame {

View File

@@ -242,7 +242,11 @@ void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *edi
d->m_ui.buttonLayout->addWidget(d->m_submitButton); d->m_ui.buttonLayout->addWidget(d->m_submitButton);
if (!d->m_submitShortcut) if (!d->m_submitShortcut)
d->m_submitShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this); d->m_submitShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this);
connect(d->m_submitShortcut, &QShortcut::activated, submitAction, &QAction::trigger); connect(d->m_submitShortcut, &QShortcut::activated,
submitAction, [submitAction] {
if (submitAction->isEnabled())
submitAction->trigger();
});
} }
if (diffAction) { if (diffAction) {
if (debug) if (debug)