//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// copyright : (C) 2008 by Eran Ifrah
// file name : async_executable_cmd.cpp
//
// -------------------------------------------------------------------------
// A
// _____ _ _ _ _
// / __ \ | | | | (_) |
// | / \/ ___ __| | ___| | _| |_ ___
// | | / _ \ / _ |/ _ \ | | | __/ _ )
// | \__/\ (_) | (_| | __/ |___| | || __/
// \____/\___/ \__,_|\___\_____/_|\__\___|
//
// F i l e
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#include <wx/xrc/xmlres.h>
#include <wx/tokenzr.h>
#include "async_executable_cmd.h"
const wxEventType wxEVT_ASYNC_PROC_ADDLINE = XRCID("async_proc_addline");
const wxEventType wxEVT_ASYNC_PROC_ADDERRLINE = XRCID("async_proc_adderrline");
const wxEventType wxEVT_ASYNC_PROC_STARTED = XRCID("async_proc_started");
const wxEventType wxEVT_ASYNC_PROC_ENDED = XRCID("async_proc_ended");
static int AsyncExeTimerID = wxNewId();
BEGIN_EVENT_TABLE(AsyncExeCmd, wxEvtHandler)
EVT_TIMER(AsyncExeTimerID, AsyncExeCmd::OnTimer)
END_EVENT_TABLE()
AsyncExeCmd::AsyncExeCmd(wxEvtHandler *owner)
: m_proc(NULL)
, m_owner(owner)
, m_busy(false)
, m_stop(false)
{
m_timer = new wxTimer(this, AsyncExeTimerID);
}
AsyncExeCmd::~AsyncExeCmd()
{
delete m_timer;
m_timer = NULL;
if (m_proc) {
delete m_proc;
m_proc = NULL;
}
};
void AsyncExeCmd::AppendLine(const wxString &line, bool isErr)
{
if ( !m_owner)
return;
wxCommandEvent event(isErr ? wxEVT_ASYNC_PROC_ADDERRLINE : wxEVT_ASYNC_PROC_ADDLINE);
event.SetEventObject(this);
event.SetString(line);
m_owner->ProcessEvent(event);
}
void AsyncExeCmd::Stop()
{
m_stop = true;
//kill the build process
if (m_proc) {
m_proc->Terminate();
}
}
void AsyncExeCmd::SendStartMsg()
{
if ( !m_owner)
return;
wxCommandEvent event(wxEVT_ASYNC_PROC_STARTED);
event.SetEventObject(this);
wxString msg;
msg << wxT("Current working directory: ") << wxGetCwd() << wxT("\n");
msg << wxT("Running program: ") << m_cmdLine << wxT("\n");
event.SetString(msg);
m_owner->ProcessEvent(event);
}
void AsyncExeCmd::SendEndMsg(int exitCode)
{
if ( !m_owner)
return;
wxCommandEvent event(wxEVT_ASYNC_PROC_ENDED);
event.SetEventObject(this);
wxString message(wxT("Program exited with return code: "));
message << exitCode << wxT("\n");
event.SetString(message);
m_owner->ProcessEvent(event);
}
void AsyncExeCmd::OnTimer(wxTimerEvent &event)
{
wxUnusedVar(event);
if ( m_stop ) {
m_proc->Terminate();
return;
}
PrintOutput();
}
void AsyncExeCmd::PrintOutput()
{
if (m_proc->GetRedirect()) {
wxString data, errors;
m_proc->HasInput(data, errors);
DoPrintOutput(data, errors);
}
}
void AsyncExeCmd::DoPrintOutput(const wxString &out, const wxString &err)
{
if (!out.IsEmpty()) {
wxStringTokenizer tt(out, wxT("\n"));
while (tt.HasMoreTokens()) {
AppendLine(tt.NextToken() + wxT("\n"));
}
}
if (!err.IsEmpty()) {
wxStringTokenizer tt(err, wxT("\n"));
while (tt.HasMoreTokens()) {
AppendLine(tt.NextToken() + wxT("\n"), true);
}
}
}
void AsyncExeCmd::ProcessEnd(wxProcessEvent& event)
{
//read all input before stopping the timer
if ( !m_stop ) {
if (m_proc->GetRedirect()) {
wxString err;
wxString out;
m_proc->ReadAll(out, err);
DoPrintOutput(out, err);
out.Empty();
err.Empty();
}
}
//stop the timer if needed
if(m_proc->GetRedirect()){
m_timer->Stop();
}
m_busy = false;
m_stop = false;
SendEndMsg(event.GetExitCode());
}
void AsyncExeCmd::Execute(const wxString &cmdLine, bool hide, bool redirect)
{
m_cmdLine = cmdLine;
SetBusy(true);
SendStartMsg();
m_proc = new clProcess(wxNewId(), m_cmdLine, redirect);
if (m_proc) {
if (m_proc->Start(hide) == 0) {
delete m_proc;
m_proc = NULL;
SetBusy(false);
} else {
//process started successfully, start timer if needed
if(m_proc->GetRedirect()){
m_timer->Start(10);
}
}
}
}
void AsyncExeCmd::Terminate()
{
m_proc->Terminate();
}