MyExternalCmdExecDialog.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00025 // This class is written based on 'exec' sample of wxWidgets library.
00026 
00027 #include <config.h>
00028 #include "panoinc_WX.h"
00029 #include "panoinc.h"
00030 
00031 #include <errno.h>
00032 
00033 #include "base_wx/wxPlatform.h"
00034 
00035 #include "wx/ffile.h"
00036 #include "wx/process.h"
00037 #include "wx/mimetype.h"
00038 
00039 #ifdef __WINDOWS__
00040     #include "wx/dde.h"
00041         #include <windows.h>
00042         #include <tlhelp32.h>   //needed to pause process on windows
00043 #else
00044         #include <sys/types.h>  
00045         #include <signal.h>     //needed to pause on unix - kill function
00046         #include <unistd.h> //needed to separate the process group of make
00047 #endif // __WINDOWS__
00048 
00049 // Slightly reworked fix for BUG_2075064 
00050 #ifdef __WXMAC__
00051         #include <iostream>
00052         #include <stdio.h>
00053         #include "wx/utils.h"
00054 #endif
00055 
00056 #include "MyExternalCmdExecDialog.h"
00057 #include "hugin/config_defaults.h"
00058 
00059 // Slightly reworked fix for BUG_2075064 
00060 using namespace std;
00061 
00062 
00063 // This wx internal bug is in versions of wxmac>2.8.8 on Leopard on ppc.
00064 /*#if defined __WXMAC__ && defined __ppc__
00065         #define __HUGIN_WORKAROUND_BUG_2075064
00066         DEBUG_DEBUG("Setting the __HUGIN_WORKAROUND_BUG_2075064");
00067 #endif
00068 */
00069 // ----------------------------------------------------------------------------
00070 // constants
00071 // ----------------------------------------------------------------------------
00072 
00073 // IDs for the controls and the menu commands
00074 enum
00075 {
00076     // control ids
00077     Exec_Btn_Cancel = 1000,
00078 };
00079 
00080 // ----------------------------------------------------------------------------
00081 // event tables and other macros for wxWidgets
00082 // ----------------------------------------------------------------------------
00083 
00084 
00085 BEGIN_EVENT_TABLE(MyExecPanel, wxPanel)
00086 //    EVT_IDLE(MyExecDialog::OnIdle)
00087     EVT_TIMER(wxID_ANY, MyExecPanel::OnTimer)
00088 END_EVENT_TABLE()
00089 
00090 
00091 // ============================================================================
00092 // implementation
00093 // ============================================================================
00094 
00095 
00096 // frame constructor
00097 MyExecPanel::MyExecPanel(wxWindow * parent)
00098        : wxPanel(parent),
00099          m_timerIdleWakeUp(this)
00100 {
00101     m_pidLast = 0;
00102 
00103     wxBoxSizer * topsizer = new wxBoxSizer( wxVERTICAL );
00104     // create the listbox in which we will show misc messages as they come
00105 #ifdef HUGIN_EXEC_LISTBOX
00106     m_lbox = new wxListBox(this, wxID_ANY);
00107     m_lbox->Append(m_currLine);
00108 #else
00109     m_textctrl = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY);
00110     m_lastLineStart = 0;
00111 #endif
00112     
00113 #ifdef __WXMAC__
00114     wxFont font(10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00115 #else
00116     wxFont font(8, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00117 #endif
00118     
00119     if ( font.Ok() ) {
00120 #ifdef HUGIN_EXEC_LISTBOX
00121         m_lbox->SetFont(font);
00122 #else
00123         m_textctrl->SetFont(font);
00124 #endif
00125     }
00126 
00127 #ifdef HUGIN_EXEC_LISTBOX
00128     topsizer->Add(m_lbox, 1, wxEXPAND | wxALL, 10);
00129 #else
00130     topsizer->Add(m_textctrl, 1, wxEXPAND | wxALL, 10);
00131 #endif
00132 
00133 //    topsizer->Add( new wxButton(this, wxID_CANCEL, _("Cancel")),
00134 //                  0, wxALL | wxALIGN_RIGHT, 10);
00135 
00136     SetSizer( topsizer );
00137 //    topsizer->SetSizeHints( this );
00138 }
00139 
00140 void MyExecPanel::KillProcess()
00141 {
00142     if (m_pidLast) {
00143 #ifdef __WXMSW__
00144         DEBUG_DEBUG("Killing process " << m_pidLast << " with sigkill");
00145         wxKillError rc = wxProcess::Kill(m_pidLast, wxSIGKILL, wxKILL_CHILDREN);
00146 #else
00147         DEBUG_DEBUG("Killing process " << m_pidLast << " with sigterm");
00148         wxKillError rc = wxProcess::Kill(m_pidLast, wxSIGTERM, wxKILL_CHILDREN);
00149 #endif
00150         if ( rc != wxKILL_OK ) {
00151             static const wxChar *errorText[] =
00152             {
00153                 _T(""), // no error
00154                 _T("signal not supported"),
00155                 _T("permission denied"),
00156                 _T("no such process"),
00157                 _T("unspecified error"),
00158             };
00159 
00160             wxLogError(_("Failed to kill process %ld, error %d: %s"),
00161                         m_pidLast, rc, errorText[rc]);
00162         }
00163     }
00164 }
00165 
00167 void MyExecPanel::PauseProcess(bool pause)
00168 {
00169 #ifdef __WXMSW__
00170         HANDLE hProcessSnapshot = NULL;
00171         HANDLE hThreadSnapshot = NULL; 
00172         PROCESSENTRY32 pEntry = {0};
00173         THREADENTRY32 tEntry = {0};
00174 
00175         //we take a snapshot of all system processes
00176         hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
00177 
00178         if (hProcessSnapshot == INVALID_HANDLE_VALUE)
00179                 wxLogError(_("Error pausing process %ld, code 1"),m_pidLast);
00180         else
00181         {
00182                 pEntry.dwSize = sizeof(PROCESSENTRY32);
00183                 tEntry.dwSize = sizeof(THREADENTRY32);
00184                 
00185                 //we traverse all processes in the system
00186                 if(Process32First(hProcessSnapshot, &pEntry))
00187                 {
00188                         do
00189                         {
00190                                 //we pause threads of the main (make) process and its children (nona,enblend...)
00191                                 if((pEntry.th32ProcessID == m_pidLast) || (pEntry.th32ParentProcessID == m_pidLast))
00192                                 {
00193                                         //we take a snapshot of all system threads
00194                                         hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 
00195                                         if (hThreadSnapshot == INVALID_HANDLE_VALUE)
00196                                                 wxLogError(_("Error pausing process %ld, code 2"),m_pidLast);
00197 
00198                                         //we traverse all threads
00199                                         if(Thread32First(hThreadSnapshot, &tEntry))
00200                                         {
00201                                                 do
00202                                                 {
00203                                                         //we find all threads of the process
00204                                                         if(tEntry.th32OwnerProcessID == pEntry.th32ProcessID)
00205                                                         {
00206                                                                 HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, tEntry.th32ThreadID);
00207                                                                 if(pause)
00208                                                                         SuspendThread(hThread);
00209                                                                 else
00210                                                                         ResumeThread(hThread);
00211                                                                 CloseHandle(hThread);
00212                                                         }
00213                                                 }while(Thread32Next(hThreadSnapshot, &tEntry));
00214                                         }
00215                                         CloseHandle(hThreadSnapshot);
00216                                 }
00217                         }while(Process32Next(hProcessSnapshot, &pEntry));
00218                 }
00219         }
00220         CloseHandle(hProcessSnapshot);
00221 #else
00222         //send the process group a pause/cont signal
00223         if(pause)
00224                 killpg(m_pidLast,SIGSTOP);
00225         else
00226                 killpg(m_pidLast,SIGCONT);
00227 #endif //__WXMSW__
00228 }
00229 
00230 void MyExecPanel::ContinueProcess()
00231 {
00232         PauseProcess(false);
00233 }
00234 
00235 long MyExecPanel::GetPid()
00236 {
00237         return m_pidLast;
00238 }
00239 
00240 int MyExecPanel::ExecWithRedirect(wxString cmd)
00241 {
00242     if ( !cmd )
00243         return -1;
00244 
00245 // Slightly reworked fix for BUG_2075064 
00246 #if defined __WXMAC__ && defined __ppc__
00247         int osVersionMajor;
00248         int osVersionMinor;
00249         
00250         int os = wxGetOsVersion(&osVersionMajor, &osVersionMinor);
00251         
00252          cout << "osVersionCheck: os is " << os << "\n"  << endl;
00253          cout << "osVersionCheck: osVersionMajor = " << osVersionMajor << endl;
00254          cout << "osVersionCheck: osVersionMinor = " << osVersionMinor << endl;
00255         if ((osVersionMajor == 0x10) && (osVersionMinor >= 0x50))
00256         {
00257                 //let the child process exit without becoming zombie
00258                 //may do some harm to internal handling by wxWidgets, but hey it's not working anyway
00259                 signal(SIGCHLD,SIG_IGN);
00260                 cout <<  "osVersionCheck: Leopard loop 1" << endl;
00261         }
00262         else
00263         {
00264                 cout <<  "osVersionCheck: Tiger loop 1" << endl;
00265         }       
00266 #endif
00267     
00268     MyPipedProcess *process = new MyPipedProcess(this, cmd);
00269     m_pidLast = wxExecute(cmd, wxEXEC_ASYNC|wxEXEC_MAKE_GROUP_LEADER, process);
00270     if ( m_pidLast == 0 )
00271     {
00272         wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
00273         delete process;
00274         return -1;
00275     }
00276     else
00277     {
00278         AddAsyncProcess(process);
00279 #ifndef __WINDOWS__
00280                 //on linux we put the new process into a separate group, 
00281                 //so it can be paused with all it's children at the same time
00282                 setpgid(m_pidLast,m_pidLast);   
00283 #endif
00284     }
00285     m_cmdLast = cmd;
00286     return 0;   
00287 }
00288 
00289 void MyExecPanel::AddAsyncProcess(MyPipedProcess *process)
00290 {
00291     if ( m_running.IsEmpty() )
00292     {
00293         // we want to start getting the timer events to ensure that a
00294         // steady stream of idle events comes in -- otherwise we
00295         // wouldn't be able to poll the child process input
00296         m_timerIdleWakeUp.Start(200);
00297     }
00298     //else: the timer is already running
00299 
00300     m_running.Add(process);
00301 }
00302 
00303 
00304 void MyExecPanel::RemoveAsyncProcess(MyPipedProcess *process)
00305 {
00306     m_running.Remove(process);
00307 
00308     if ( m_running.IsEmpty() )
00309     {
00310         // we don't need to get idle events all the time any more
00311         m_timerIdleWakeUp.Stop();
00312     }
00313 }
00314 
00315 
00316 // ----------------------------------------------------------------------------
00317 // various helpers
00318 // ----------------------------------------------------------------------------
00319 
00320 void MyExecPanel::AddToOutput(wxInputStream & s)
00321 {
00322     DEBUG_TRACE("");
00323     wxTextInputStream ts(s);
00324 #if HUGIN_EXEC_LISTBOX
00325     while(s.CanRead()) {
00326         wxChar c = ts.GetChar();
00327         if (c == '\b') {
00328             m_currLine.RemoveLast();
00329         } else if (c == 0x0d) {
00330             // back to start of line
00331             m_currLine.clear();
00332         } else if (c == '\n') {
00333             // add line to listbox and start new listbox
00334             m_lbox->SetString(m_lbox->GetCount()-1, m_currLine);
00335             m_currLine.clear();
00336             m_lbox->Append(m_currLine);
00337         } else {
00338             m_currLine.Append(c);
00339         }
00340     }
00341     m_lbox->SetString(m_lbox->GetCount()-1, m_currLine);
00342 
00343 #else
00344 
00345 #ifdef HUGIN_EXEC_AVOID_STREAM_GETCHAR
00346     while(s.CanRead()) {
00347         wxString buffer = ts.ReadLine() + wxT("\n");
00348         while(true) {
00349             int pos = buffer.Find(wxChar('\b'));
00350             if(pos == wxNOT_FOUND)
00351                 break;
00352             else if(pos == 0)
00353                 buffer = buffer.erase(0,1);
00354             else //if(pos > 0)
00355                 buffer = buffer.erase(pos-1,2);
00356         }
00357         buffer = buffer.AfterLast(wxChar(0x0d));
00358         m_textctrl->AppendText(buffer);
00359     }
00360     return;
00361 #endif
00362     bool lastCR= false;
00363     wxString currLine = m_textctrl->GetRange(m_lastLineStart, m_textctrl->GetLastPosition());
00364     while(s.CanRead()) {
00365         wxChar c = ts.GetChar();
00366         if (c == '\b') {
00367             lastCR=false;
00368             // backspace
00369             if (currLine.size() > 0) {
00370                 if (currLine.Last() != wxChar('\n') )
00371                     currLine.Trim();
00372             }
00373             /*
00374             if (m_output.Last() != '\n') {
00375                 m_output.RemoveLast();
00376             }*/
00377         } else if (c == 0x0d) {
00378             lastCR=true;
00379 #ifndef __WXMSW__
00380             // back to start of line
00381              if (currLine.Last() != wxChar('\n') ) {
00382                 currLine = currLine.BeforeLast('\n');
00383                 if(currLine.size() > 0) {
00384                     currLine.Append('\n');
00385                 }
00386              }
00387 #endif
00388         } else if (c == '\n') {
00389             currLine.Append(c);
00390             lastCR=false;
00391         } else {
00392 #ifdef __WXMSW__
00393             if (lastCR) {
00394             // back to start of line
00395                 if (currLine.Last() != wxChar('\n') ) {
00396                     currLine = currLine.BeforeLast('\n');
00397                     if(currLine.size() > 0) {
00398                         currLine.Append('\n');
00399                     }
00400                 }
00401             }
00402 #endif
00403             currLine.Append(c);
00404             lastCR=false;
00405         }
00406     }
00407 
00408     m_textctrl->Replace(m_lastLineStart, m_textctrl->GetLastPosition(), currLine);
00409     size_t lret = currLine.find_last_of(wxChar('\n'));
00410     if (lret > 0 && lret+1 < currLine.size()) {
00411         m_lastLineStart += lret+1;
00412     }
00413 #endif
00414 }
00415 
00416 void MyExecPanel::OnTimer(wxTimerEvent& WXUNUSED(event))
00417 {
00418 //    wxWakeUpIdle();
00419 
00420 #ifndef HUGIN_EXEC_LISTBOX
00421 //    m_textctrl->Freeze();
00422 #endif
00423     bool changed=false;
00424     size_t count = m_running.GetCount();
00425     for ( size_t n = 0; n < count; n++ )
00426     {
00427         while ( m_running[n]->IsInputAvailable() )
00428         {
00429             AddToOutput(*(m_running[n]->GetInputStream()));
00430             changed=true;
00431         }
00432         while ( m_running[n]->IsErrorAvailable() )
00433         {
00434             AddToOutput(*(m_running[n]->GetErrorStream()));
00435             changed=true;
00436         }
00437     }
00438 #ifdef HUGIN_EXEC_LISTBOX
00439 //    m_lbox->SetSelection(m_lbox->GetCount() -1);
00440 #else
00441     if (changed) {
00442         DEBUG_DEBUG("refreshing textctrl");
00443 #ifndef LINE_IO
00444 //        m_textctrl->ShowPosition(m_textctrl->GetLastPosition());
00445 //        m_textctrl->SetInsertionPoint(m_textctrl->GetLastPosition()-1);
00446 #endif
00447     }
00448 //    m_textctrl->Thaw();
00449 #endif
00450 
00451 // Slightly reworked fix for BUG_2075064
00452 #if defined __WXMAC__ && defined __ppc__
00453         int osVersionMajor;
00454         int osVersionMinor;
00455         
00456         int os = wxGetOsVersion(&osVersionMajor, &osVersionMinor);
00457         
00458         cerr << "osVersionCheck: os is " << os << "\n"  << endl;
00459         cerr << "osVersionCheck: osVersionMajor = " << osVersionMajor << endl;
00460         cerr << "osVersionCheck: osVersionMinor = " << osVersionMinor << endl;
00461 
00462         if ((osVersionMajor == 0x10) && (osVersionMinor >= 0x50))
00463     {   
00464                 cerr <<  "osVersionCheck: Leopard loop 2" << endl;      
00465                 if(m_pidLast)
00466                 {
00467                         if(kill((pid_t)m_pidLast,0)!=0) //if not pid exists
00468                         {
00469                                 DEBUG_DEBUG("Found terminated process: " << (pid_t)m_pidLast)
00470             
00471                                 // probably should clean up the wxProcess object which was newed when the process was launched.
00472                                 // for now, nevermind the tiny memory leak... it's a hack to workaround the bug anyway
00473             
00474                                 //notify dialog that it's finished.
00475                                 if (this->GetParent()) {
00476                                         wxProcessEvent event( wxID_ANY, m_pidLast, 0); // assume 0 exit code
00477                                         event.SetEventObject( this );
00478                                         DEBUG_TRACE("Sending wxProcess event");   
00479                                         this->GetParent()->ProcessEvent( event );
00480                                 }
00481                         }
00482                 }
00483         }
00484         else
00485         {
00486                 cerr <<  "osVersionCheck: Tiger loop 2" << endl;
00487         }
00488 #endif
00489 }
00490 
00491 void MyExecPanel::OnProcessTerminated(MyPipedProcess *process, int pid, int status)
00492 {
00493     DEBUG_TRACE("process terminated: pid " << pid << " exit code:" << status);
00494     // show the rest of the output
00495     AddToOutput(*(process->GetInputStream()));
00496     AddToOutput(*(process->GetErrorStream()));
00497 
00498     RemoveAsyncProcess(process);
00499     // send termination to other parent
00500     if (this->GetParent()) {
00501         wxProcessEvent event( wxID_ANY, pid, status);
00502         event.SetEventObject( this );
00503         DEBUG_TRACE("Sending wxProcess event");   
00504         this->GetParent()->GetEventHandler()->ProcessEvent( event );
00505     }
00506 
00507 }
00508 
00509 MyExecPanel::~MyExecPanel() {
00510 #ifdef HUGIN_EXEC_LISTBOX
00511     delete m_lbox;
00512 #else
00513     delete m_textctrl;
00514 #endif
00515 }
00516 
00517 bool MyExecPanel::SaveLog(const wxString &filename)
00518 {
00519     return m_textctrl->SaveFile(filename);
00520 };
00521 
00522 void MyExecPanel::CopyLogToClipboard()
00523 {
00524     m_textctrl->SelectAll();
00525     m_textctrl->Copy();
00526 };
00527 
00528 // ----------------------------------------------------------------------------
00529 // MyProcess
00530 // ----------------------------------------------------------------------------
00531 
00532 void MyProcess::OnTerminate(int pid, int status)
00533 {
00534     DEBUG_TRACE("");
00535    
00536 //    wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
00537 //                pid, m_cmd.c_str(), status);
00538 
00539     // we're not needed any more
00540     delete this;
00541 }
00542 
00543 // ----------------------------------------------------------------------------
00544 // MyPipedProcess
00545 // ----------------------------------------------------------------------------
00546 /*
00547 bool MyPipedProcess::HasInput(wxString & my_stdout, wxString & my_stderr)
00548 {
00549     bool hasInput = false;
00550 
00551     if ( IsInputAvailable() )
00552     {
00553         wxTextInputStream tis(*GetInputStream());
00554 
00555         // this assumes that the output is always line buffered
00556         wxString msg;
00557         //msg << m_cmd << _T(" (my_stdout): ") << tis.ReadLine();
00558         my_stdout << tis.ReadLine();
00559 
00560 //        m_parent->GetLogListBox()->Append(msg);
00561 
00562         hasInput = true;
00563     }
00564 
00565     if ( IsErrorAvailable() )
00566     {
00567         wxTextInputStream tis(*GetErrorStream());
00568 
00569         // this assumes that the output is always line buffered
00570         wxString msg;
00571         //msg << m_cmd << _T(" (stderr): ") << tis.ReadLine();
00572         my_stderr << tis.ReadLine();
00573 
00574 //        m_parent->GetLogListBox()->Append(msg);
00575 
00576         hasInput = true;
00577     }
00578 
00579     return hasInput;
00580 }
00581 */
00582 
00583 void MyPipedProcess::OnTerminate(int pid, int status)
00584 {
00585     DEBUG_DEBUG("Process " << pid << " terminated with return code: " << status);
00586     m_parent->OnProcessTerminated(this, pid, status);
00587 
00588     MyProcess::OnTerminate(pid, status);
00589 }
00590 
00591 // ==============================================================================
00592 // MyExecDialog
00593 
00594 BEGIN_EVENT_TABLE(MyExecDialog, wxDialog)
00595     EVT_BUTTON(wxID_CANCEL,  MyExecDialog::OnCancel)
00596     EVT_END_PROCESS(wxID_ANY, MyExecDialog::OnProcessTerminate)
00597 END_EVENT_TABLE()
00598 
00599 
00600 
00601 
00602 MyExecDialog::MyExecDialog(wxWindow * parent, const wxString& title, const wxPoint& pos, const wxSize& size)
00603     : wxDialog(parent, wxID_ANY, title, pos, size, wxRESIZE_BORDER | wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU)
00604 {
00605 
00606     wxBoxSizer * topsizer = new wxBoxSizer( wxVERTICAL );
00607     m_execPanel = new MyExecPanel(this);
00608     m_cancelled = false;
00609     
00610     topsizer->Add(m_execPanel, 1, wxEXPAND | wxALL, 2);
00611 
00612     topsizer->Add( new wxButton(this, wxID_CANCEL, _("Cancel")),
00613                    0, wxALL | wxALIGN_RIGHT, 10);
00614 
00615 #ifdef __WXMSW__
00616     // wxFrame does have a strange background color on Windows..
00617     this->SetBackgroundColour(m_execPanel->GetBackgroundColour());
00618 #endif
00619     SetSizer( topsizer );
00620 //    topsizer->SetSizeHints( this );
00621 }
00622 
00623 void MyExecDialog::OnProcessTerminate(wxProcessEvent & event)
00624 {
00625     DEBUG_DEBUG("Process terminated with return code: " << event.GetExitCode());
00626     if(wxConfigBase::Get()->Read(wxT("CopyLogToClipboard"), 0l)==1l)
00627     {
00628         m_execPanel->CopyLogToClipboard();
00629     };
00630     if (m_cancelled) {
00631         EndModal(HUGIN_EXIT_CODE_CANCELLED);
00632     } else {
00633         EndModal(event.GetExitCode());
00634     }
00635 }
00636 
00637 void MyExecDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
00638 {
00639     DEBUG_DEBUG("Cancel Pressed");
00640     m_cancelled = true;
00641     m_execPanel->KillProcess();
00642 }
00643 
00644 
00645 int MyExecDialog::ExecWithRedirect(wxString cmd)
00646 {
00647     if (m_execPanel->ExecWithRedirect(cmd) == -1) {
00648         return -1;
00649     }
00650 
00651     return ShowModal();
00652 }
00653 
00654 MyExecDialog::~MyExecDialog() {
00655     delete m_execPanel;
00656 }
00657 
00658 int MyExecuteCommandOnDialog(wxString command, wxString args, wxWindow* parent,
00659                              wxString title, bool isQuoted)
00660 {
00661     if(!isQuoted)
00662     {
00663         command = hugin_utils::wxQuoteFilename(command);
00664     };
00665     wxString cmdline = command + wxT(" ") + args;
00666     MyExecDialog dlg(parent, title,
00667                      wxDefaultPosition, wxSize(640, 400));
00668 #ifdef __WXMAC__
00669     dlg.CentreOnParent();
00670 #endif
00671     return dlg.ExecWithRedirect(cmdline);
00672 }
00673 
00674 //----------
00675 
00676 BEGIN_EVENT_TABLE(MyExternalCmdExecDialog, wxDialog)
00677 EVT_IDLE(MyExternalCmdExecDialog::OnIdle)
00678 EVT_TIMER(wxID_ANY, MyExternalCmdExecDialog::OnTimer)
00679 END_EVENT_TABLE()
00680 
00681 
00682 MyExternalCmdExecDialog::MyExternalCmdExecDialog(wxWindow* parent, 
00683                                                  wxWindowID id, 
00684                                                  const wxString& title, 
00685                                                  const wxPoint& pos,
00686                                                  const wxSize& size,
00687                                                  long style,
00688                                                  const wxString& name)
00689 : wxDialog(parent, id, title, pos, size, style, name),
00690 m_timerIdleWakeUp(this)
00691 {
00692     //m_lbox = new wxListBox(this, wxID_ANY);
00693     wxBoxSizer *m_sizer = new wxBoxSizer(wxVERTICAL);
00694     this->SetSizer(m_sizer);
00695     m_tbox = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY);
00696 #ifdef __WXMAC__
00697     wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00698 #else
00699     wxFont font(8, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00700 #endif
00701     if ( font.Ok() )
00702         m_tbox->SetFont(font);
00703     m_sizer->Add(m_tbox, 1, wxEXPAND);
00704     m_sizer->AddSpacer(30);
00705 }
00706 
00707 
00708 int MyExternalCmdExecDialog::ShowModal(const wxString &cmd)
00709 {
00710     process = new HuginPipedProcess(this, cmd);
00711 
00712     processID = wxExecute(cmd, wxEXEC_ASYNC, process);
00713     if (!processID)
00714     {
00715         delete process;
00716         EndModal(-1);
00717     }
00718     else
00719     {
00720         m_timerIdleWakeUp.Start(200);
00721     }
00722     return wxDialog::ShowModal();
00723 }
00724 
00725 int MyExternalCmdExecDialog::Execute(const wxString & cmd)
00726 {
00727     process = new HuginPipedProcess(this, cmd);
00728 
00729     m_exitCode = 0;
00730     processID = wxExecute(cmd, wxEXEC_ASYNC, process);
00731     if (!processID)
00732     {
00733         delete process;
00734         EndModal(-1);
00735     }
00736     else
00737     {
00738         m_timerIdleWakeUp.Start(200);
00739     }
00740     return wxDialog::ShowModal();
00741 }
00742 
00743 int MyExternalCmdExecDialog::GetExitCode()
00744 {
00745     return m_exitCode;
00746 }
00747 
00748 void MyExternalCmdExecDialog::SetExitCode(int ret)
00749 {
00750     m_exitCode = ret;
00751 }
00752 
00753 
00754 void MyExternalCmdExecDialog::OnTimer(wxTimerEvent& WXUNUSED(event))
00755 {
00756     wxWakeUpIdle();
00757 }
00758 
00759 void MyExternalCmdExecDialog::OnIdle(wxIdleEvent& event)
00760 {
00761     if ( process->HasInput() )
00762     {
00763         event.RequestMore();
00764     }
00765 
00766 // hack for wxmac 2.7.0-1
00767 #ifdef __WXMAC__ 
00768     wxTextCtrl * tb = GetLogTextBox();
00769     tb->SetInsertionPoint(tb->GetLastPosition()); 
00770 #endif
00771 }
00772 
00773 MyExternalCmdExecDialog::~MyExternalCmdExecDialog() {
00774     delete m_tbox;
00775 }
00776 
00777 //----------
00778 
00779 bool HuginPipedProcess::HasInput()
00780 {
00781     bool hasInput = false;
00782 
00783     wxTextInputStream tis(*GetInputStream());
00784 //    if ( IsInputAvailable() )
00785     if (GetInputStream()->CanRead() )
00786     {
00787         DEBUG_DEBUG("input available");
00788         wxTextCtrl * tb = m_parent->GetLogTextBox();
00789         
00790         // does not assume line buffered stream.
00791         // tries to handle backspace chars properly
00792         wxString text = tb->GetValue();
00793         
00794         while(GetInputStream()->CanRead())
00795         {
00796             wxChar c = tis.GetChar();
00797             if (c) {
00798                 if (c == '\b') {
00799                     // backspace
00800                     if (text.Last() != '\n') {
00801                         text.RemoveLast();
00802                     }
00803                 } else if (c == 0x0d) {
00804                     // back to start of line
00805                     text = text.BeforeLast('\n') + wxT("\n");
00806                 } else {
00807                     text.Append(c);
00808                 }
00809             }
00810         }
00811         
00812         tb->SetValue(text);
00813         tb->ShowPosition(tb->GetLastPosition());
00814         hasInput = true;
00815     }
00816 
00817     wxTextInputStream tes(*GetErrorStream());
00818 //    if ( IsErrorAvailable() )
00819     if (GetErrorStream()->CanRead())
00820     {
00821         DEBUG_DEBUG("error available");
00822 
00823         // does not assume line buffered stream.
00824         // tries to handle backspace chars properly
00825         wxTextCtrl * tb = m_parent->GetLogTextBox();
00826         wxString text = tb->GetValue();
00827 
00828         while(GetErrorStream()->CanRead())
00829         {
00830             wxChar c = tes.GetChar();
00831             if (c) {
00832                 if (c == '\b') {
00833                     // backspace
00834                     if (text.Last() != '\n') {
00835                         text.RemoveLast();
00836                     }
00837                 } else if (c == 0x0d) {
00838                     // back to start of line
00839                     text = text.BeforeLast('\n') + wxT("\n");
00840                 } else {
00841                     text.Append(c);
00842                 }
00843             }
00844         }
00845 
00846         tb->SetValue(text);
00847         tb->ShowPosition(tb->GetLastPosition());
00848         hasInput = true;
00849     }
00850     return hasInput;
00851 }
00852 
00853 void HuginPipedProcess::OnTerminate(int pid, int status)
00854 {
00855     // show the rest of the output
00856     while ( HasInput() ) ;
00857 
00858     m_parent->SetExitCode(status);
00859     m_parent->EndModal(-3);
00860 
00861     // we're not needed any more
00862     delete this;
00863 }
00864 

Generated on Thu Oct 2 01:25:32 2014 for Hugintrunk by  doxygen 1.3.9.1