2011-03-25 09:25:17 +01:00
/**************************************************************************
* *
* * This file is part of Qt Creator
* *
2012-01-26 18:33:46 +01:00
* * Copyright ( c ) 2012 Nokia Corporation and / or its subsidiary ( - ies ) .
2011-03-25 09:25:17 +01:00
* *
2011-11-02 15:59:12 +01:00
* * Contact : Nokia Corporation ( qt - info @ 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-11-02 15:59:12 +01:00
* * Nokia at qt - info @ nokia . com .
2011-03-25 09:25:17 +01:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-03-11 12:22:57 +01:00
# include "qmlprofilerengine.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-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-10-31 16:42:31 +01:00
# include <qmljsdebugclient/qdeclarativeoutputparser.h>
2011-05-04 16:50:24 +02:00
2012-02-15 10:42:41 +01:00
# include <QMainWindow>
# include <QMessageBox>
# include <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 ;
2012-02-24 10:47:17 +01:00
QmlProfilerStateManager * m_profilerState ;
2011-05-20 13:36:16 +02:00
AbstractQmlProfilerRunner * m_runner ;
2011-07-28 10:38:39 +02:00
QTimer m_noDebugOutputTimer ;
2011-10-31 16:42:31 +01:00
QmlJsDebugClient : : QDeclarativeOutputParser m_outputParser ;
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 ( ) ;
2012-02-17 19:05:11 +01:00
conf . port = rc1 - > debuggerAspect ( ) - > qmlDebugServerPort ( ) ;
2011-07-05 12:14:41 +02:00
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 ( ) ;
2012-02-17 19:05:11 +01:00
conf . port = rc2 - > debuggerAspect ( ) - > qmlDebugServerPort ( ) ;
2011-07-05 12:14:41 +02:00
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
{
2012-02-24 10:47:17 +01:00
d - > m_profilerState = 0 ;
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-10-31 16:42:31 +01:00
d - > m_outputParser . setNoOutputText ( ApplicationLauncher : : msgWinCannotRetrieveDebuggingOutput ( ) ) ;
2012-02-21 15:47:55 +01:00
connect ( & d - > m_outputParser , SIGNAL ( waitingForConnectionOnPort ( quint16 ) ) ,
this , SLOT ( processIsRunning ( quint16 ) ) ) ;
connect ( & d - > m_outputParser , SIGNAL ( waitingForConnectionViaOst ( ) ) ,
2011-10-31 16:42:31 +01:00
this , SLOT ( processIsRunning ( ) ) ) ;
connect ( & d - > m_outputParser , SIGNAL ( noOutputMessage ( ) ) ,
this , SLOT ( processIsRunning ( ) ) ) ;
connect ( & d - > m_outputParser , SIGNAL ( errorMessage ( QString ) ) ,
this , SLOT ( wrongSetupMessageBox ( QString ) ) ) ;
2011-03-11 12:22:57 +01:00
}
QmlProfilerEngine : : ~ QmlProfilerEngine ( )
{
2012-02-24 10:47:17 +01:00
if ( d - > m_profilerState & & d - > m_profilerState - > currentState ( ) = = QmlProfilerStateManager : : AppRunning )
2011-03-11 12:22:57 +01:00
stop ( ) ;
delete d ;
}
2011-07-25 14:49:07 +02:00
bool QmlProfilerEngine : : start ( )
2011-03-11 12:22:57 +01:00
{
2012-02-24 10:47:17 +01:00
QTC_ASSERT ( d - > m_profilerState , return false ) ;
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
2012-02-24 10:47:17 +01:00
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : AppStarting ) ;
2011-07-21 10:42:34 +02:00
if ( QmlProjectManager : : QmlProjectRunConfiguration * rc =
qobject_cast < QmlProjectManager : : QmlProjectRunConfiguration * > ( runConfiguration ( ) ) ) {
if ( rc - > observerPath ( ) . isEmpty ( ) ) {
QmlProjectManager : : QmlProjectPlugin : : showQmlObserverToolWarning ( ) ;
2012-02-24 10:47:17 +01:00
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : Idle ) ;
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. " ) ) ;
2012-02-24 10:47:17 +01:00
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : Idle ) ;
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 ) {
2012-02-24 10:47:17 +01:00
connect ( d - > m_runner , SIGNAL ( stopped ( ) ) , this , SLOT ( processEnded ( ) ) ) ;
2011-09-14 13:12:25 +02:00
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
2012-02-24 10:47:17 +01:00
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : AppRunning ) ;
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 ( )
{
2012-02-24 10:47:17 +01:00
QTC_ASSERT ( d - > m_profilerState , return ) ;
switch ( d - > m_profilerState - > currentState ( ) ) {
case QmlProfilerStateManager : : AppRunning : {
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : AppStopRequested ) ;
break ;
}
case QmlProfilerStateManager : : AppReadyToStop : {
cancelProcess ( ) ;
break ;
}
case QmlProfilerStateManager : : AppKilled : {
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : Idle ) ;
break ;
}
default :
qDebug ( ) < < tr ( " Unexpected engine stop from state %1 in %2:%3 " ) . arg ( d - > m_profilerState - > currentStateAsString ( ) , QString ( __FILE__ ) , QString : : number ( __LINE__ ) ) ;
break ;
2011-05-04 16:50:24 +02:00
}
2011-03-11 12:22:57 +01:00
}
2012-02-24 10:47:17 +01:00
void QmlProfilerEngine : : processEnded ( )
2011-03-24 12:42:15 +01:00
{
2012-02-24 10:47:17 +01:00
QTC_ASSERT ( d - > m_profilerState , return ) ;
2011-07-13 14:47:34 +02:00
2012-02-24 10:47:17 +01:00
switch ( d - > m_profilerState - > currentState ( ) ) {
case QmlProfilerStateManager : : AppRunning : {
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : AppKilled ) ;
AnalyzerManager : : stopTool ( ) ;
2011-03-24 12:42:15 +01:00
2012-02-24 10:47:17 +01:00
emit finished ( ) ;
break ;
}
case QmlProfilerStateManager : : AppStopped :
// fallthrough
case QmlProfilerStateManager : : AppKilled : {
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : Idle ) ;
break ;
}
default :
qDebug ( ) < < tr ( " Process died unexpectedly from state %1 in %2:%3 " ) . arg ( d - > m_profilerState - > currentStateAsString ( ) , QString ( __FILE__ ) , QString : : number ( __LINE__ ) ) ;
break ;
}
2011-04-14 15:23:17 +02:00
}
2011-04-06 12:26:19 +02:00
2012-02-24 10:47:17 +01:00
void QmlProfilerEngine : : cancelProcess ( )
2011-05-20 13:36:16 +02:00
{
2012-02-24 10:47:17 +01:00
QTC_ASSERT ( d - > m_profilerState , return ) ;
2011-04-14 16:05:41 +02:00
2012-02-24 10:47:17 +01:00
switch ( d - > m_profilerState - > currentState ( ) ) {
case QmlProfilerStateManager : : AppReadyToStop : {
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : AppStopped ) ;
break ;
}
case QmlProfilerStateManager : : AppRunning : {
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : AppKilled ) ;
break ;
}
default : {
qDebug ( ) < < tr ( " Unexpected process termination requested with state %1 in %2:%3 " ) . arg ( d - > m_profilerState - > currentStateAsString ( ) , QString ( __FILE__ ) , QString : : number ( __LINE__ ) ) ;
return ;
}
2011-04-06 12:26:19 +02:00
}
2012-02-24 10:47:17 +01:00
if ( d - > m_runner )
d - > m_runner - > stop ( ) ;
emit finished ( ) ;
2011-03-11 12:22:57 +01:00
}
2011-10-31 16:42:31 +01:00
void QmlProfilerEngine : : logApplicationMessage ( const QString & msg , Utils : : OutputFormat format )
2011-06-09 14:30:15 +02:00
{
2011-10-31 16:42:31 +01:00
emit outputReceived ( msg , format ) ;
d - > m_outputParser . processOutput ( msg ) ;
2011-06-09 14:30:15 +02:00
}
2011-10-31 16:42:31 +01:00
void QmlProfilerEngine : : wrongSetupMessageBox ( const QString & errorMessage )
2011-04-14 17:14:26 +02:00
{
2012-01-24 15:36:40 +01:00
QMessageBox * infoBox = new QMessageBox ( Core : : ICore : : mainWindow ( ) ) ;
2011-10-31 16:42:31 +01:00
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-06-09 14:30:15 +02:00
2012-02-24 10:47:17 +01:00
// KILL
d - > m_profilerState - > setCurrentState ( QmlProfilerStateManager : : AppKilled ) ;
2011-10-31 16:42:31 +01:00
AnalyzerManager : : stopTool ( ) ;
emit finished ( ) ;
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
{
2012-01-24 15:36:40 +01:00
QMessageBox * noExecWarning = new QMessageBox ( Core : : ICore : : mainWindow ( ) ) ;
2011-07-22 15:26:40 +02:00
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 ( ) ;
}
2012-02-21 15:47:55 +01:00
void QmlProfilerEngine : : processIsRunning ( quint16 port )
2011-07-28 10:38:39 +02:00
{
d - > m_noDebugOutputTimer . stop ( ) ;
2012-02-21 15:47:55 +01:00
QTC_ASSERT ( port = = 0
| | port = = d - > m_runner - > debugPort ( ) ,
qWarning ( ) < < " Port " < < port < < " from application output does not match "
< < startParameters ( ) . connParams . port < < " from start parameters. " ) ;
if ( port > 0 )
emit processRunning ( port ) ;
else
emit processRunning ( d - > m_runner - > debugPort ( ) ) ;
2011-07-28 10:38:39 +02:00
}
2012-02-24 10:47:17 +01:00
////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerEngine : : registerProfilerStateManager ( QmlProfilerStateManager * profilerState )
{
// disconnect old
if ( d - > m_profilerState ) {
disconnect ( d - > m_profilerState , SIGNAL ( stateChanged ( ) ) , this , SLOT ( profilerStateChanged ( ) ) ) ;
}
d - > m_profilerState = profilerState ;
// connect
if ( d - > m_profilerState ) {
connect ( d - > m_profilerState , SIGNAL ( stateChanged ( ) ) , this , SLOT ( profilerStateChanged ( ) ) ) ;
}
}
void QmlProfilerEngine : : profilerStateChanged ( )
{
switch ( d - > m_profilerState - > currentState ( ) ) {
case QmlProfilerStateManager : : AppReadyToStop : {
cancelProcess ( ) ;
break ;
}
case QmlProfilerStateManager : : Idle : {
// for some reason the engine is not deleted when it goes to idle
// a new one will be created on the next run, and this one will
// be only deleted if the new one is running the same app
// we need to explictly disconnect it here without expecting a deletion
// as it will not be run any more, otherwise we will get funny side effects
registerProfilerStateManager ( 0 ) ;
break ;
}
default :
break ;
}
}
2011-05-20 13:36:16 +02:00
} // namespace Internal
} // namespace QmlProfiler