2011-03-25 09:25:17 +01:00
/**************************************************************************
* *
* * This file is part of Qt Creator
* *
* * Copyright ( c ) 2011 Nokia Corporation and / or its subsidiary ( - ies ) .
* *
2011-05-06 15:05:37 +02:00
* * Contact : Nokia Corporation ( info @ qt . nokia . com )
2011-03-25 09:25:17 +01:00
* *
* *
* * GNU Lesser General Public License Usage
* *
2011-07-06 15:48:52 +00:00
* * This file may be used under the terms of the GNU Lesser General Public
* * License version 2.1 as published by the Free Software Foundation and
* * appearing in the file LICENSE . LGPL included in the packaging of this file .
* * Please review the following information to ensure the GNU Lesser General
* * Public License version 2.1 requirements will be met :
* * http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
2011-03-25 09:25:17 +01:00
* *
* * In addition , as a special exception , Nokia gives you certain additional
2011-07-06 15:48:52 +00:00
* * rights . These rights are described in the Nokia Qt LGPL Exception
2011-03-25 09:25:17 +01:00
* * version 1.1 , included in the file LGPL_EXCEPTION . txt in this package .
* *
2011-07-06 15:48:52 +00:00
* * Other Usage
* *
* * Alternatively , this file may be used in accordance with the terms and
* * conditions contained in a signed written agreement between you and Nokia .
* *
2011-03-25 09:25:17 +01:00
* * If you have questions regarding the use of this file , please contact
2011-05-06 15:05:37 +02:00
* * Nokia at info @ qt . nokia . com .
2011-03-25 09:25:17 +01:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-03-11 12:22:57 +01:00
# include "qmlprofilerengine.h"
2011-06-28 15:51:20 +02:00
# include "canvas/qdeclarativecanvas_p.h"
# include "canvas/qdeclarativecontext2d_p.h"
# include "canvas/qdeclarativetiledcanvas_p.h"
2011-06-09 14:34:26 +02:00
# include "codaqmlprofilerrunner.h"
2011-06-28 15:51:20 +02:00
# include "localqmlprofilerrunner.h"
2011-06-27 17:18:55 +02:00
# include "remotelinuxqmlprofilerrunner.h"
2011-06-28 15:51:20 +02:00
# include "qmlprofilerplugin.h"
# include "qmlprofilertool.h"
2011-03-11 12:22:57 +01:00
2011-03-24 12:42:15 +01:00
# include <analyzerbase/analyzermanager.h>
2011-06-09 14:30:15 +02:00
# include <coreplugin/icore.h>
2011-05-04 16:50:24 +02:00
# include <utils/qtcassert.h>
2011-06-28 15:51:20 +02:00
# include <coreplugin/helpmanager.h>
2011-07-05 12:14:41 +02:00
# include <qmlprojectmanager/qmlprojectrunconfiguration.h>
2011-07-21 10:42:34 +02:00
# include <qmlprojectmanager/qmlprojectplugin.h>
2011-07-05 12:14:41 +02:00
# include <projectexplorer/localapplicationruncontrol.h>
# include <projectexplorer/applicationrunconfiguration.h>
# include <qt4projectmanager/qt-s60/s60devicedebugruncontrol.h>
# include <qt4projectmanager/qt-s60/s60devicerunconfiguration.h>
2011-05-04 16:50:24 +02:00
2011-06-09 14:30:15 +02:00
# include <QtGui/QMainWindow>
2011-06-28 15:51:20 +02:00
# include <QtGui/QMessageBox>
2011-07-28 10:38:39 +02:00
# include <QtCore/QTimer>
2011-03-11 12:22:57 +01:00
2011-06-30 13:44:22 +02:00
using namespace Analyzer ;
2011-07-05 12:14:41 +02:00
using namespace ProjectExplorer ;
2011-06-30 13:44:22 +02:00
2011-05-20 13:36:16 +02:00
namespace QmlProfiler {
namespace Internal {
2011-05-04 16:50:24 +02:00
//
// QmlProfilerEnginePrivate
//
2011-05-20 13:36:16 +02:00
class QmlProfilerEngine : : QmlProfilerEnginePrivate
{
public :
QmlProfilerEnginePrivate ( QmlProfilerEngine * qq ) : q ( qq ) , m_runner ( 0 ) { }
2011-07-25 10:36:21 +02:00
~ QmlProfilerEnginePrivate ( ) { delete m_runner ; }
2011-05-20 13:36:16 +02:00
bool attach ( const QString & address , uint port ) ;
2011-06-09 14:34:26 +02:00
static AbstractQmlProfilerRunner * createRunner ( ProjectExplorer : : RunConfiguration * runConfiguration ,
QObject * parent ) ;
2011-05-20 13:36:16 +02:00
QmlProfilerEngine * q ;
2011-07-05 12:14:41 +02:00
//AnalyzerStartParameters m_params;
2011-05-20 13:36:16 +02:00
AbstractQmlProfilerRunner * m_runner ;
bool m_running ;
bool m_fetchingData ;
2011-07-25 10:36:21 +02:00
bool m_fetchDataFromStart ;
2011-05-20 13:36:16 +02:00
bool m_delayedDelete ;
2011-07-28 10:38:39 +02:00
QTimer m_noDebugOutputTimer ;
2011-05-20 13:36:16 +02:00
} ;
2011-06-09 14:34:26 +02:00
AbstractQmlProfilerRunner *
2011-07-05 12:14:41 +02:00
QmlProfilerEngine : : QmlProfilerEnginePrivate : : createRunner ( ProjectExplorer : : RunConfiguration * runConfiguration ,
2011-06-09 14:34:26 +02:00
QObject * parent )
{
AbstractQmlProfilerRunner * runner = 0 ;
2011-09-14 13:12:25 +02:00
if ( ! runConfiguration ) // attaching
return 0 ;
2011-07-05 12:14:41 +02:00
if ( QmlProjectManager : : QmlProjectRunConfiguration * rc1 =
qobject_cast < QmlProjectManager : : QmlProjectRunConfiguration * > ( runConfiguration ) ) {
// This is a "plain" .qmlproject.
LocalQmlProfilerRunner : : Configuration conf ;
conf . executable = rc1 - > observerPath ( ) ;
conf . executableArguments = rc1 - > viewerArguments ( ) ;
conf . workingDirectory = rc1 - > workingDirectory ( ) ;
conf . environment = rc1 - > environment ( ) ;
conf . port = rc1 - > qmlDebugServerPort ( ) ;
runner = new LocalQmlProfilerRunner ( conf , parent ) ;
} else if ( LocalApplicationRunConfiguration * rc2 =
qobject_cast < LocalApplicationRunConfiguration * > ( runConfiguration ) ) {
// FIXME: Check.
LocalQmlProfilerRunner : : Configuration conf ;
conf . executable = rc2 - > executable ( ) ;
conf . executableArguments = rc2 - > commandLineArguments ( ) ;
conf . workingDirectory = rc2 - > workingDirectory ( ) ;
conf . environment = rc2 - > environment ( ) ;
conf . port = rc2 - > qmlDebugServerPort ( ) ;
runner = new LocalQmlProfilerRunner ( conf , parent ) ;
} else if ( Qt4ProjectManager : : S60DeviceRunConfiguration * s60Config =
qobject_cast < Qt4ProjectManager : : S60DeviceRunConfiguration * > ( runConfiguration ) ) {
runner = new CodaQmlProfilerRunner ( s60Config , parent ) ;
} else if ( RemoteLinux : : RemoteLinuxRunConfiguration * rmConfig =
qobject_cast < RemoteLinux : : RemoteLinuxRunConfiguration * > ( runConfiguration ) ) {
runner = new RemoteLinuxQmlProfilerRunner ( rmConfig , parent ) ;
} else {
2011-07-29 12:00:11 +02:00
QTC_CHECK ( false ) ;
2011-06-09 14:34:26 +02:00
}
return runner ;
}
2011-05-20 13:36:16 +02:00
2011-05-04 16:50:24 +02:00
//
// QmlProfilerEngine
//
2011-07-05 12:14:41 +02:00
QmlProfilerEngine : : QmlProfilerEngine ( IAnalyzerTool * tool ,
2011-09-14 13:12:25 +02:00
const Analyzer : : AnalyzerStartParameters & sp ,
ProjectExplorer : : RunConfiguration * runConfiguration )
: IAnalyzerEngine ( tool , sp , runConfiguration )
2011-04-04 14:39:28 +02:00
, d ( new QmlProfilerEnginePrivate ( this ) )
2011-03-11 12:22:57 +01:00
{
d - > m_running = false ;
2011-04-06 12:26:19 +02:00
d - > m_fetchingData = false ;
2011-07-25 10:36:21 +02:00
d - > m_fetchDataFromStart = false ;
2011-04-14 16:05:41 +02:00
d - > m_delayedDelete = false ;
2011-07-28 10:38:39 +02:00
// Only wait 4 seconds for the 'Waiting for connection' on application ouput, then just try to connect
// (application output might be redirected / blocked)
d - > m_noDebugOutputTimer . setSingleShot ( true ) ;
d - > m_noDebugOutputTimer . setInterval ( 4000 ) ;
connect ( & d - > m_noDebugOutputTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( processIsRunning ( ) ) ) ;
2011-03-11 12:22:57 +01:00
}
QmlProfilerEngine : : ~ QmlProfilerEngine ( )
{
if ( d - > m_running )
stop ( ) ;
delete d ;
}
2011-07-25 14:49:07 +02:00
bool QmlProfilerEngine : : start ( )
2011-03-11 12:22:57 +01:00
{
2011-07-25 10:36:21 +02:00
if ( d - > m_runner ) {
delete d - > m_runner ;
d - > m_runner = 0 ;
}
2011-07-21 10:42:34 +02:00
if ( QmlProjectManager : : QmlProjectRunConfiguration * rc =
qobject_cast < QmlProjectManager : : QmlProjectRunConfiguration * > ( runConfiguration ( ) ) ) {
if ( rc - > observerPath ( ) . isEmpty ( ) ) {
QmlProjectManager : : QmlProjectPlugin : : showQmlObserverToolWarning ( ) ;
2011-07-22 15:26:40 +02:00
AnalyzerManager : : stopTool ( ) ;
2011-07-25 14:49:07 +02:00
return false ;
2011-07-21 10:42:34 +02:00
}
}
2011-07-05 12:14:41 +02:00
d - > m_runner = QmlProfilerEnginePrivate : : createRunner ( runConfiguration ( ) , this ) ;
2011-07-22 15:26:40 +02:00
if ( LocalQmlProfilerRunner * qmlRunner = qobject_cast < LocalQmlProfilerRunner * > ( d - > m_runner ) ) {
if ( ! qmlRunner - > hasExecutable ( ) ) {
2011-07-22 15:52:59 +02:00
showNonmodalWarning ( tr ( " No executable file to launch. " ) ) ;
2011-07-22 15:26:40 +02:00
AnalyzerManager : : stopTool ( ) ;
2011-07-25 14:49:07 +02:00
return false ;
2011-07-22 15:26:40 +02:00
}
}
2011-05-04 16:50:24 +02:00
2011-09-14 13:12:25 +02:00
if ( d - > m_runner ) {
connect ( d - > m_runner , SIGNAL ( stopped ( ) ) , this , SLOT ( stopped ( ) ) ) ;
connect ( d - > m_runner , SIGNAL ( appendMessage ( QString , Utils : : OutputFormat ) ) ,
this , SLOT ( logApplicationMessage ( QString , Utils : : OutputFormat ) ) ) ;
d - > m_runner - > start ( ) ;
d - > m_noDebugOutputTimer . start ( ) ;
} else {
emit processRunning ( startParameters ( ) . connParams . port ) ;
}
2011-05-04 16:50:24 +02:00
2011-03-11 12:22:57 +01:00
d - > m_running = true ;
2011-04-14 16:05:41 +02:00
d - > m_delayedDelete = false ;
2011-07-05 12:56:49 +02:00
2011-07-25 10:36:21 +02:00
if ( d - > m_fetchDataFromStart ) {
d - > m_fetchingData = true ;
}
2011-07-05 12:56:49 +02:00
AnalyzerManager : : handleToolStarted ( ) ;
2011-08-25 16:30:36 +02:00
emit starting ( this ) ;
2011-07-25 14:49:07 +02:00
return true ;
2011-03-11 12:22:57 +01:00
}
void QmlProfilerEngine : : stop ( )
{
2011-07-25 10:36:21 +02:00
// keep the flag for the next restart
d - > m_fetchDataFromStart = d - > m_fetchingData ;
2011-04-14 16:05:41 +02:00
if ( d - > m_fetchingData ) {
if ( d - > m_running )
d - > m_delayedDelete = true ;
2011-06-09 14:34:26 +02:00
// will result in dataReceived() call
2011-04-06 12:26:19 +02:00
emit stopRecording ( ) ;
2011-05-04 16:50:24 +02:00
} else {
2011-04-06 12:26:19 +02:00
finishProcess ( ) ;
2011-05-04 16:50:24 +02:00
}
2011-03-11 12:22:57 +01:00
}
2011-05-04 16:50:24 +02:00
void QmlProfilerEngine : : stopped ( )
2011-03-24 12:42:15 +01:00
{
2011-07-25 10:36:21 +02:00
// if it was killed, preserve recording flag
if ( d - > m_running )
d - > m_fetchDataFromStart = d - > m_fetchingData ;
2011-07-13 14:47:34 +02:00
// user feedback
if ( d - > m_running & & d - > m_fetchingData ) {
2011-07-22 15:52:59 +02:00
showNonmodalWarning ( tr ( " Application finished before loading profiled data. \n Please use the stop button instead. " ) ) ;
2011-07-13 14:47:34 +02:00
}
2011-04-06 12:26:19 +02:00
d - > m_running = false ;
2011-07-04 10:50:44 +02:00
AnalyzerManager : : stopTool ( ) ; // FIXME: Needed?
2011-04-06 12:26:19 +02:00
emit finished ( ) ;
2011-03-24 12:42:15 +01:00
}
2011-04-14 15:23:17 +02:00
void QmlProfilerEngine : : setFetchingData ( bool b )
{
2011-04-06 12:26:19 +02:00
d - > m_fetchingData = b ;
2011-07-25 10:36:21 +02:00
if ( ! d - > m_running )
d - > m_fetchDataFromStart = b ;
2011-04-14 15:23:17 +02:00
}
2011-04-06 12:26:19 +02:00
2011-05-20 13:36:16 +02:00
void QmlProfilerEngine : : dataReceived ( )
{
2011-04-14 16:05:41 +02:00
if ( d - > m_delayedDelete )
finishProcess ( ) ;
d - > m_delayedDelete = false ;
}
2011-04-06 12:26:19 +02:00
void QmlProfilerEngine : : finishProcess ( )
2011-03-11 12:22:57 +01:00
{
2011-04-14 17:14:26 +02:00
// user stop?
2011-04-14 15:23:17 +02:00
if ( d - > m_running ) {
d - > m_running = false ;
2011-09-14 13:12:25 +02:00
if ( d - > m_runner )
d - > m_runner - > stop ( ) ;
2011-04-06 12:26:19 +02:00
emit finished ( ) ;
}
2011-03-11 12:22:57 +01:00
}
2011-06-09 14:30:15 +02:00
void QmlProfilerEngine : : filterApplicationMessage ( const QString & msg )
{
static const QString qddserver = QLatin1String ( " QDeclarativeDebugServer: " ) ;
static const QString cannotRetrieveDebuggingOutput = ProjectExplorer : : ApplicationLauncher : : msgWinCannotRetrieveDebuggingOutput ( ) ;
const int index = msg . indexOf ( qddserver ) ;
if ( index ! = - 1 ) {
2011-07-28 10:38:39 +02:00
// we're actually getting debug output
d - > m_noDebugOutputTimer . stop ( ) ;
2011-06-09 14:30:15 +02:00
QString status = msg ;
status . remove ( 0 , index + qddserver . length ( ) ) ; // chop of 'QDeclarativeDebugServer: '
static QString waitingForConnection = QLatin1String ( " Waiting for connection " ) ;
static QString unableToListen = QLatin1String ( " Unable to listen " ) ;
static QString debuggingNotEnabled = QLatin1String ( " Ignoring \" -qmljsdebugger= " ) ;
static QString debuggingNotEnabled2 = QLatin1String ( " Ignoring \" -qmljsdebugger= " ) ; // There is (was?) a bug in one of the error strings - safest to handle both
static QString connectionEstablished = QLatin1String ( " Connection established " ) ;
QString errorMessage ;
if ( status . startsWith ( waitingForConnection ) ) {
2011-07-28 10:38:39 +02:00
processIsRunning ( ) ;
2011-06-09 14:30:15 +02:00
} else if ( status . startsWith ( unableToListen ) ) {
//: Error message shown after 'Could not connect ... debugger:"
errorMessage = tr ( " The port seems to be in use. " ) ;
} else if ( status . startsWith ( debuggingNotEnabled ) | | status . startsWith ( debuggingNotEnabled2 ) ) {
//: Error message shown after 'Could not connect ... debugger:"
errorMessage = tr ( " The application is not set up for QML/JS debugging. " ) ;
} else if ( status . startsWith ( connectionEstablished ) ) {
// nothing to do
} else {
qWarning ( ) < < " Unknown QDeclarativeDebugServer status message: " < < status ;
}
if ( ! errorMessage . isEmpty ( ) ) {
Core : : ICore * const core = Core : : ICore : : instance ( ) ;
QMessageBox * infoBox = new QMessageBox ( core - > mainWindow ( ) ) ;
infoBox - > setIcon ( QMessageBox : : Critical ) ;
infoBox - > setWindowTitle ( tr ( " Qt Creator " ) ) ;
//: %1 is detailed error message
infoBox - > setText ( tr ( " Could not connect to the in-process QML debugger: \n %1 " )
. arg ( errorMessage ) ) ;
infoBox - > setStandardButtons ( QMessageBox : : Ok | QMessageBox : : Help ) ;
infoBox - > setDefaultButton ( QMessageBox : : Ok ) ;
infoBox - > setModal ( true ) ;
connect ( infoBox , SIGNAL ( finished ( int ) ) ,
this , SLOT ( wrongSetupMessageBoxFinished ( int ) ) ) ;
infoBox - > show ( ) ;
2011-08-26 12:10:40 +02:00
d - > m_running = false ;
AnalyzerManager : : stopTool ( ) ;
emit finished ( ) ;
2011-06-09 14:30:15 +02:00
}
} else if ( msg . contains ( cannotRetrieveDebuggingOutput ) ) {
// we won't get debugging output, so just try to connect ...
2011-07-28 10:38:39 +02:00
processIsRunning ( ) ;
2011-06-09 14:30:15 +02:00
}
}
2011-06-10 16:34:06 +02:00
void QmlProfilerEngine : : logApplicationMessage ( const QString & msg , Utils : : OutputFormat format )
2011-04-14 17:14:26 +02:00
{
2011-06-10 16:34:06 +02:00
emit outputReceived ( msg , format ) ;
2011-06-09 14:30:15 +02:00
filterApplicationMessage ( msg ) ;
2011-04-14 17:14:26 +02:00
}
2011-05-20 13:36:16 +02:00
2011-06-28 09:28:14 +02:00
void QmlProfilerEngine : : wrongSetupMessageBoxFinished ( int button )
{
if ( button = = QMessageBox : : Help ) {
Core : : HelpManager * helpManager = Core : : HelpManager : : instance ( ) ;
2011-08-02 12:48:48 +02:00
helpManager - > handleHelpRequest ( " qthelp://com.nokia.qtcreator/doc/creator-debugging-qml.html "
" #setting-up-qml-debugging " ) ;
2011-06-28 09:28:14 +02:00
}
}
2011-07-22 15:52:59 +02:00
void QmlProfilerEngine : : showNonmodalWarning ( const QString & warningMsg )
2011-07-22 15:26:40 +02:00
{
Core : : ICore * const core = Core : : ICore : : instance ( ) ;
QMessageBox * noExecWarning = new QMessageBox ( core - > mainWindow ( ) ) ;
noExecWarning - > setIcon ( QMessageBox : : Warning ) ;
noExecWarning - > setWindowTitle ( tr ( " QML Profiler " ) ) ;
2011-07-22 15:52:59 +02:00
noExecWarning - > setText ( warningMsg ) ;
2011-07-22 15:26:40 +02:00
noExecWarning - > setStandardButtons ( QMessageBox : : Ok ) ;
noExecWarning - > setDefaultButton ( QMessageBox : : Ok ) ;
noExecWarning - > setModal ( false ) ;
noExecWarning - > show ( ) ;
}
2011-07-28 10:38:39 +02:00
void QmlProfilerEngine : : processIsRunning ( )
{
d - > m_noDebugOutputTimer . stop ( ) ;
emit processRunning ( d - > m_runner - > debugPort ( ) ) ;
}
2011-05-20 13:36:16 +02:00
} // namespace Internal
} // namespace QmlProfiler