2011-01-18 16:45:42 +01:00
/**************************************************************************
* *
* * This file is part of Qt Creator
* *
* * Copyright ( c ) 2011 Nokia Corporation and / or its subsidiary ( - ies ) .
* *
* * Contact : Nokia Corporation ( qt - info @ nokia . com )
* *
* * No Commercial Usage
* *
* * This file contains pre - release code and may not be distributed .
* * You may use this file in accordance with the terms and conditions
* * contained in the Technology Preview License Agreement accompanying
* * this package .
* *
* * GNU Lesser General Public License Usage
* *
* * Alternatively , this file may be used under the terms of the GNU Lesser
* * General Public License version 2.1 as published by the Free Software
* * Foundation and appearing in the file LICENSE . LGPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU Lesser General Public License version 2.1 requirements
* * will be met : http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
* *
* * In addition , as a special exception , Nokia gives you certain additional
* * rights . These rights are described in the Nokia Qt LGPL Exception
* * version 1.1 , included in the file LGPL_EXCEPTION . txt in this package .
* *
* * If you have questions regarding the use of this file , please contact
* * Nokia at qt - info @ nokia . com .
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "codaruncontrol.h"
# include "s60deployconfiguration.h"
# include "s60devicerunconfiguration.h"
2011-02-07 14:26:34 +01:00
# include "codadevice.h"
# include "codamessage.h"
2011-01-18 16:45:42 +01:00
# include "qt4buildconfiguration.h"
# include "qt4symbiantarget.h"
# include "qt4target.h"
# include "qtoutputformatter.h"
2011-02-04 12:08:19 +01:00
# include "symbiandevicemanager.h"
2011-01-18 16:45:42 +01:00
# include <coreplugin/icore.h>
# include <utils/qtcassert.h>
2011-03-28 19:58:13 +02:00
# include <projectexplorer/projectexplorerconstants.h>
2011-01-18 16:45:42 +01:00
2011-02-07 09:45:54 +01:00
# include <symbianutils/symbiandevicemanager.h>
2011-01-18 16:45:42 +01:00
# include <QtCore/QDir>
# include <QtCore/QFileInfo>
# include <QtCore/QScopedPointer>
2011-01-21 12:48:51 +01:00
# include <QtCore/QTimer>
2011-01-18 16:45:42 +01:00
# include <QtGui/QMessageBox>
# include <QtGui/QMainWindow>
# include <QtNetwork/QTcpSocket>
using namespace ProjectExplorer ;
using namespace Qt4ProjectManager ;
using namespace Qt4ProjectManager : : Internal ;
2011-02-07 14:26:34 +01:00
using namespace Coda ;
2011-01-18 16:45:42 +01:00
2011-02-07 14:14:57 +01:00
enum { debug = 0 } ;
2011-01-18 16:45:42 +01:00
CodaRunControl : : CodaRunControl ( RunConfiguration * runConfiguration , const QString & mode ) :
S60RunControlBase ( runConfiguration , mode ) ,
m_port ( 0 ) ,
m_state ( StateUninit )
{
const S60DeviceRunConfiguration * s60runConfig = qobject_cast < S60DeviceRunConfiguration * > ( runConfiguration ) ;
QTC_ASSERT ( s60runConfig , return ) ;
const S60DeployConfiguration * activeDeployConf = qobject_cast < S60DeployConfiguration * > ( s60runConfig - > qt4Target ( ) - > activeDeployConfiguration ( ) ) ;
QTC_ASSERT ( activeDeployConf , return ) ;
2011-01-25 09:18:45 +01:00
S60DeployConfiguration : : CommunicationChannel channel = activeDeployConf - > communicationChannel ( ) ;
if ( channel = = S60DeployConfiguration : : CommunicationCodaTcpConnection ) {
m_address = activeDeployConf - > deviceAddress ( ) ;
m_port = activeDeployConf - > devicePort ( ) . toInt ( ) ;
} else if ( channel = = S60DeployConfiguration : : CommunicationCodaSerialConnection ) {
m_serialPort = activeDeployConf - > serialPortName ( ) ;
} else {
QTC_ASSERT ( false , return ) ;
}
2011-01-18 16:45:42 +01:00
}
2011-02-08 12:12:26 +01:00
CodaRunControl : : ~ CodaRunControl ( )
{
}
2011-01-18 16:45:42 +01:00
bool CodaRunControl : : doStart ( )
{
2011-01-25 09:18:45 +01:00
if ( m_address . isEmpty ( ) & & m_serialPort . isEmpty ( ) ) {
2011-01-18 16:45:42 +01:00
cancelProgress ( ) ;
QString msg = tr ( " No device is connected. Please connect a device and try again. " ) ;
appendMessage ( msg , NormalMessageFormat ) ;
return false ;
}
appendMessage ( tr ( " Executable file: %1 " ) . arg ( msgListFile ( executableFileName ( ) ) ) ,
NormalMessageFormat ) ;
return true ;
}
bool CodaRunControl : : isRunning ( ) const
{
return m_state > = StateConnecting ;
}
2011-03-28 19:58:13 +02:00
QIcon CodaRunControl : : icon ( ) const
{
return QIcon ( ProjectExplorer : : Constants : : ICON_DEBUG_SMALL ) ;
}
2011-01-18 16:45:42 +01:00
bool CodaRunControl : : setupLauncher ( )
{
2011-02-07 14:26:34 +01:00
QTC_ASSERT ( ! m_codaDevice , return false ) ;
2011-01-18 16:45:42 +01:00
2011-01-25 09:18:45 +01:00
if ( m_serialPort . length ( ) ) {
2011-02-04 12:08:19 +01:00
// We get the port from SymbianDeviceManager
2011-02-15 16:05:52 +01:00
appendMessage ( tr ( " Connecting to '%1'... " ) . arg ( m_serialPort ) , NormalMessageFormat ) ;
2011-03-02 09:38:17 +01:00
m_codaDevice = SymbianUtils : : SymbianDeviceManager : : instance ( ) - > getCodaDevice ( m_serialPort ) ;
2011-03-15 10:24:25 +01:00
if ( m_codaDevice . isNull ( ) ) {
appendMessage ( tr ( " Unable to create CODA connection. Please try again. " ) , ErrorMessageFormat ) ;
return false ;
}
if ( ! m_codaDevice - > device ( ) - > isOpen ( ) ) {
2011-02-14 16:36:05 +01:00
appendMessage ( tr ( " Could not open serial device: %1 " ) . arg ( m_codaDevice - > device ( ) - > errorString ( ) ) , ErrorMessageFormat ) ;
2011-01-25 09:18:45 +01:00
return false ;
}
2011-02-07 09:45:54 +01:00
connect ( SymbianUtils : : SymbianDeviceManager : : instance ( ) , SIGNAL ( deviceRemoved ( const SymbianUtils : : SymbianDevice ) ) ,
this , SLOT ( deviceRemoved ( SymbianUtils : : SymbianDevice ) ) ) ;
2011-02-07 14:14:57 +01:00
connect ( m_codaDevice . data ( ) , SIGNAL ( error ( QString ) ) , this , SLOT ( slotError ( QString ) ) ) ;
connect ( m_codaDevice . data ( ) , SIGNAL ( logMessage ( QString ) ) , this , SLOT ( slotTrkLogMessage ( QString ) ) ) ;
connect ( m_codaDevice . data ( ) , SIGNAL ( tcfEvent ( Coda : : CodaEvent ) ) , this , SLOT ( slotCodaEvent ( Coda : : CodaEvent ) ) ) ;
connect ( m_codaDevice . data ( ) , SIGNAL ( serialPong ( QString ) ) , this , SLOT ( slotSerialPong ( QString ) ) ) ;
2011-01-25 09:18:45 +01:00
m_state = StateConnecting ;
2011-02-07 14:26:34 +01:00
m_codaDevice - > sendSerialPing ( false ) ;
2011-01-25 09:18:45 +01:00
} else {
2011-02-04 12:08:19 +01:00
// For TCP we don't use device manager, we just set it up directly
2011-03-04 13:43:25 +01:00
m_codaDevice = QSharedPointer < Coda : : CodaDevice > ( new Coda : : CodaDevice , & QObject : : deleteLater ) ; // finishRunControl, which deletes m_codaDevice, can get called from within a coda callback, so need to use deleteLater
2011-02-04 12:08:19 +01:00
connect ( m_codaDevice . data ( ) , SIGNAL ( error ( QString ) ) , this , SLOT ( slotError ( QString ) ) ) ;
connect ( m_codaDevice . data ( ) , SIGNAL ( logMessage ( QString ) ) , this , SLOT ( slotTrkLogMessage ( QString ) ) ) ;
2011-02-07 14:14:57 +01:00
connect ( m_codaDevice . data ( ) , SIGNAL ( tcfEvent ( Coda : : CodaEvent ) ) , this , SLOT ( slotCodaEvent ( Coda : : CodaEvent ) ) ) ;
2011-02-04 12:08:19 +01:00
2011-02-07 14:26:34 +01:00
const QSharedPointer < QTcpSocket > codaSocket ( new QTcpSocket ) ;
m_codaDevice - > setDevice ( codaSocket ) ;
codaSocket - > connectToHost ( m_address , m_port ) ;
2011-01-25 09:18:45 +01:00
m_state = StateConnecting ;
appendMessage ( tr ( " Connecting to %1:%2... " ) . arg ( m_address ) . arg ( m_port ) , NormalMessageFormat ) ;
}
2011-03-09 12:06:20 +01:00
QTimer : : singleShot ( 5000 , this , SLOT ( checkForTimeout ( ) ) ) ;
2011-02-07 14:14:57 +01:00
if ( debug )
m_codaDevice - > setVerbose ( debug ) ;
2011-01-18 16:45:42 +01:00
return true ;
}
void CodaRunControl : : doStop ( )
{
switch ( m_state ) {
case StateUninit :
case StateConnecting :
case StateConnected :
finishRunControl ( ) ;
break ;
case StateProcessRunning :
QTC_ASSERT ( ! m_runningProcessId . isEmpty ( ) , return ) ;
2011-02-07 14:26:34 +01:00
m_codaDevice - > sendRunControlTerminateCommand ( CodaCallback ( ) ,
2011-01-18 16:45:42 +01:00
m_runningProcessId . toAscii ( ) ) ;
break ;
}
}
void CodaRunControl : : slotError ( const QString & error )
{
appendMessage ( tr ( " Error: %1 " ) . arg ( error ) , ErrorMessageFormat ) ;
finishRunControl ( ) ;
}
void CodaRunControl : : slotTrkLogMessage ( const QString & log )
{
2011-02-08 10:42:03 +01:00
if ( debug > 1 )
2011-01-18 16:45:42 +01:00
qDebug ( " CODA log: %s " , qPrintable ( log . size ( ) > 200 ? log . left ( 200 ) . append ( QLatin1String ( " ... " ) ) : log ) ) ;
}
void CodaRunControl : : slotSerialPong ( const QString & message )
{
2011-02-08 10:42:03 +01:00
if ( debug > 1 )
2011-01-18 16:45:42 +01:00
qDebug ( ) < < " CODA serial pong: " < < message ;
2011-03-16 10:03:52 +01:00
handleConnected ( ) ;
2011-01-18 16:45:42 +01:00
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : slotCodaEvent ( const CodaEvent & event )
2011-01-18 16:45:42 +01:00
{
if ( debug )
qDebug ( ) < < " CODA event: " < < " Type: " < < event . type ( ) < < " Message: " < < event . toString ( ) ;
switch ( event . type ( ) ) {
2011-03-16 10:03:52 +01:00
case CodaEvent : : LocatorHello :
handleConnected ( ) ;
break ;
2011-02-07 14:26:34 +01:00
case CodaEvent : : RunControlContextRemoved :
2011-01-18 16:45:42 +01:00
handleContextRemoved ( event ) ;
break ;
2011-02-07 14:26:34 +01:00
case CodaEvent : : RunControlContextAdded :
2011-01-18 16:45:42 +01:00
m_state = StateProcessRunning ;
reportLaunchFinished ( ) ;
handleContextAdded ( event ) ;
break ;
2011-02-07 14:26:34 +01:00
case CodaEvent : : RunControlSuspended :
2011-01-18 16:45:42 +01:00
handleContextSuspended ( event ) ;
break ;
2011-02-07 14:26:34 +01:00
case CodaEvent : : RunControlModuleLoadSuspended :
2011-01-18 16:45:42 +01:00
handleModuleLoadSuspended ( event ) ;
break ;
2011-02-07 14:26:34 +01:00
case CodaEvent : : LoggingWriteEvent :
2011-01-18 16:45:42 +01:00
handleLogging ( event ) ;
break ;
default :
if ( debug )
qDebug ( ) < < " CODA event not handled " < < event . type ( ) ;
break ;
}
}
void CodaRunControl : : initCommunication ( )
{
2011-02-07 14:26:34 +01:00
m_codaDevice - > sendLoggingAddListenerCommand ( CodaCallback ( this , & CodaRunControl : : handleAddListener ) ) ;
2011-01-18 16:45:42 +01:00
}
2011-03-16 10:03:52 +01:00
void CodaRunControl : : handleConnected ( )
{
if ( m_state > = StateConnected )
return ;
m_state = StateConnected ;
appendMessage ( tr ( " Connected. " ) , NormalMessageFormat ) ;
setProgress ( maxProgress ( ) * 0.80 ) ;
initCommunication ( ) ;
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : handleContextRemoved ( const CodaEvent & event )
2011-01-18 16:45:42 +01:00
{
const QVector < QByteArray > removedItems
2011-02-07 14:26:34 +01:00
= static_cast < const CodaRunControlContextRemovedEvent & > ( event ) . ids ( ) ;
2011-01-18 16:45:42 +01:00
if ( ! m_runningProcessId . isEmpty ( )
& & removedItems . contains ( m_runningProcessId . toAscii ( ) ) ) {
appendMessage ( tr ( " Process has finished. " ) , NormalMessageFormat ) ;
finishRunControl ( ) ;
}
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : handleContextAdded ( const CodaEvent & event )
2011-01-18 16:45:42 +01:00
{
2011-02-07 14:26:34 +01:00
typedef CodaRunControlContextAddedEvent TcfAddedEvent ;
2011-01-18 16:45:42 +01:00
const TcfAddedEvent & me = static_cast < const TcfAddedEvent & > ( event ) ;
foreach ( const RunControlContext & context , me . contexts ( ) ) {
if ( context . parentId = = " root " ) //is the created context a process
m_runningProcessId = QLatin1String ( context . id ) ;
}
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : handleContextSuspended ( const CodaEvent & event )
2011-01-18 16:45:42 +01:00
{
2011-02-07 14:26:34 +01:00
typedef CodaRunControlContextSuspendedEvent TcfSuspendEvent ;
2011-01-18 16:45:42 +01:00
const TcfSuspendEvent & me = static_cast < const TcfSuspendEvent & > ( event ) ;
switch ( me . reason ( ) ) {
2011-02-08 10:42:03 +01:00
case TcfSuspendEvent : : Other :
2011-01-18 16:45:42 +01:00
case TcfSuspendEvent : : Crash :
2011-02-07 10:12:47 +01:00
appendMessage ( tr ( " Thread has crashed: %1 " ) . arg ( QString : : fromLatin1 ( me . message ( ) ) ) , ErrorMessageFormat ) ;
2011-02-08 10:42:03 +01:00
if ( me . reason ( ) = = TcfSuspendEvent : : Crash )
stop ( ) ;
else
2011-02-23 15:16:34 +01:00
m_codaDevice - > sendRunControlResumeCommand ( CodaCallback ( ) , me . id ( ) ) ; //TODO: Should I resume automatically
2011-01-18 16:45:42 +01:00
break ;
default :
if ( debug )
qDebug ( ) < < " Context suspend not handled: " < < " Reason: " < < me . reason ( ) < < " Message: " < < me . message ( ) ;
break ;
}
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : handleModuleLoadSuspended ( const CodaEvent & event )
2011-01-18 16:45:42 +01:00
{
// Debug mode start: Continue:
2011-02-07 14:26:34 +01:00
typedef CodaRunControlModuleLoadContextSuspendedEvent TcfModuleLoadSuspendedEvent ;
2011-01-18 16:45:42 +01:00
const TcfModuleLoadSuspendedEvent & me = static_cast < const TcfModuleLoadSuspendedEvent & > ( event ) ;
if ( me . info ( ) . requireResume )
2011-02-07 14:26:34 +01:00
m_codaDevice - > sendRunControlResumeCommand ( CodaCallback ( ) , me . id ( ) ) ;
2011-01-18 16:45:42 +01:00
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : handleLogging ( const CodaEvent & event )
2011-01-18 16:45:42 +01:00
{
2011-02-07 14:26:34 +01:00
const CodaLoggingWriteEvent & me = static_cast < const CodaLoggingWriteEvent & > ( event ) ;
2011-01-18 16:45:42 +01:00
appendMessage ( me . message ( ) , StdOutFormat ) ;
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : handleAddListener ( const CodaCommandResult & result )
2011-01-18 16:45:42 +01:00
{
Q_UNUSED ( result )
2011-02-07 14:26:34 +01:00
m_codaDevice - > sendSymbianOsDataFindProcessesCommand ( CodaCallback ( this , & CodaRunControl : : handleFindProcesses ) ,
2011-02-04 11:07:15 +01:00
QByteArray ( ) ,
QByteArray : : number ( executableUid ( ) , 16 ) ) ;
2011-01-18 16:45:42 +01:00
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : handleFindProcesses ( const CodaCommandResult & result )
2011-01-18 16:45:42 +01:00
{
2011-01-21 17:30:02 +01:00
if ( result . values . size ( ) & & result . values . at ( 0 ) . type ( ) = = JsonValue : : Array & & result . values . at ( 0 ) . children ( ) . count ( ) ) {
//there are processes running. Cannot run mine
2011-01-18 16:45:42 +01:00
appendMessage ( tr ( " The process is already running on the device. Please first close it. " ) , ErrorMessageFormat ) ;
finishRunControl ( ) ;
} else {
setProgress ( maxProgress ( ) * 0.90 ) ;
2011-02-07 14:26:34 +01:00
m_codaDevice - > sendProcessStartCommand ( CodaCallback ( this , & CodaRunControl : : handleCreateProcess ) ,
2011-02-23 15:16:34 +01:00
executableName ( ) ,
executableUid ( ) ,
commandLineArguments ( ) . split ( ' ' ) ,
QString ( ) ,
true ) ;
2011-01-21 17:30:02 +01:00
appendMessage ( tr ( " Launching: %1 " ) . arg ( executableName ( ) ) , NormalMessageFormat ) ;
2011-01-18 16:45:42 +01:00
}
}
2011-02-07 14:26:34 +01:00
void CodaRunControl : : handleCreateProcess ( const CodaCommandResult & result )
2011-01-18 16:45:42 +01:00
{
2011-02-07 14:26:34 +01:00
const bool ok = result . type = = CodaCommandResult : : SuccessReply ;
2011-01-18 16:45:42 +01:00
if ( ok ) {
setProgress ( maxProgress ( ) ) ;
appendMessage ( tr ( " Launched. " ) , NormalMessageFormat ) ;
} else {
appendMessage ( tr ( " Launch failed: %1 " ) . arg ( result . toString ( ) ) , ErrorMessageFormat ) ;
finishRunControl ( ) ;
}
}
void CodaRunControl : : finishRunControl ( )
{
m_runningProcessId . clear ( ) ;
2011-02-04 12:08:19 +01:00
if ( m_codaDevice ) {
disconnect ( m_codaDevice . data ( ) , 0 , this , 0 ) ;
2011-03-02 09:38:17 +01:00
SymbianUtils : : SymbianDeviceManager : : instance ( ) - > releaseCodaDevice ( m_codaDevice ) ;
2011-02-04 12:08:19 +01:00
}
2011-01-18 16:45:42 +01:00
m_state = StateUninit ;
emit finished ( ) ;
}
QMessageBox * CodaRunControl : : createCodaWaitingMessageBox ( QWidget * parent )
{
const QString title = tr ( " Waiting for CODA " ) ;
2011-02-08 14:22:17 +01:00
const QString text = tr ( " Qt Creator is waiting for the CODA application to connect.<br> "
2011-01-18 16:45:42 +01:00
" Please make sure the application is running on "
2011-03-02 09:38:17 +01:00
" your mobile phone and the right IP address and/or port are "
2011-01-18 16:45:42 +01:00
" configured in the project settings. " ) ;
QMessageBox * mb = new QMessageBox ( QMessageBox : : Information , title , text , QMessageBox : : Cancel , parent ) ;
return mb ;
}
void CodaRunControl : : checkForTimeout ( )
{
2011-01-21 17:30:02 +01:00
if ( m_state ! = StateConnecting )
2011-01-18 16:45:42 +01:00
return ;
QMessageBox * mb = createCodaWaitingMessageBox ( Core : : ICore : : instance ( ) - > mainWindow ( ) ) ;
connect ( this , SIGNAL ( finished ( ) ) , mb , SLOT ( close ( ) ) ) ;
connect ( mb , SIGNAL ( finished ( int ) ) , this , SLOT ( cancelConnection ( ) ) ) ;
mb - > open ( ) ;
}
void CodaRunControl : : cancelConnection ( )
{
2011-01-21 17:30:02 +01:00
if ( m_state ! = StateConnecting )
2011-01-18 16:45:42 +01:00
return ;
stop ( ) ;
appendMessage ( tr ( " Canceled. " ) , ErrorMessageFormat ) ;
emit finished ( ) ;
}
2011-02-07 09:45:54 +01:00
void CodaRunControl : : deviceRemoved ( const SymbianUtils : : SymbianDevice & device )
{
2011-02-07 14:26:34 +01:00
if ( m_codaDevice & & device . portName ( ) = = m_serialPort ) {
2011-02-07 09:45:54 +01:00
QString msg = tr ( " The device '%1' has been disconnected " ) . arg ( device . friendlyName ( ) ) ;
appendMessage ( msg , ErrorMessageFormat ) ;
finishRunControl ( ) ;
}
}