X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d8e41d423d1eceea65f0c8f8bfa2c242028feb5a..790ba06b28f232abc42c4ed784df4b86bfbfe5e6:/samples/exec/exec.cpp diff --git a/samples/exec/exec.cpp b/samples/exec/exec.cpp index 9017978836..b540460720 100644 --- a/samples/exec/exec.cpp +++ b/samples/exec/exec.cpp @@ -39,12 +39,15 @@ #include "wx/msgdlg.h" #include "wx/textdlg.h" #include "wx/listbox.h" + #include "wx/filedlg.h" #endif #include "wx/txtstrm.h" #include "wx/process.h" +#include "wx/mimetype.h" + #ifdef __WINDOWS__ #include "wx/dde.h" #endif // __WINDOWS__ @@ -66,6 +69,10 @@ public: virtual bool OnInit(); }; +// Define an array of process pointers used by MyFrame +class MyPipedProcess; +WX_DEFINE_ARRAY(MyPipedProcess *, MyProcessesArray); + // Define a new frame type: this is going to be our main frame class MyFrame : public wxFrame { @@ -82,18 +89,34 @@ public: void OnAsyncExec(wxCommandEvent& event); void OnShell(wxCommandEvent& event); void OnExecWithRedirect(wxCommandEvent& event); + void OnExecWithPipe(wxCommandEvent& event); + + void OnFileExec(wxCommandEvent& event); + void OnDDEExec(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); + // polling output of async processes + void OnIdle(wxIdleEvent& event); + // for MyPipedProcess + void OnProcessTerminated(MyPipedProcess *process); wxListBox *GetLogListBox() const { return m_lbox; } private: + void ShowOutput(const wxString& cmd, + const wxArrayString& output, + const wxString& title); + + void DoAsyncExec(const wxString& cmd); + wxString m_cmdLast; wxListBox *m_lbox; + MyProcessesArray m_running; + // any class wishing to process wxWindows events must use this macro DECLARE_EVENT_TABLE() }; @@ -125,10 +148,28 @@ public: MyPipedProcess(MyFrame *parent, const wxString& cmd) : MyProcess(parent, cmd) { - m_needPipe = TRUE; + Redirect(); } virtual void OnTerminate(int pid, int status); + + virtual bool HasInput(); +}; + +// A version of MyPipedProcess which also sends input to the stdin of the +// child process +class MyPipedProcess2 : public MyPipedProcess +{ +public: + MyPipedProcess2(MyFrame *parent, const wxString& cmd, const wxString& input) + : MyPipedProcess(parent, cmd), m_input(input) + { + } + + virtual bool HasInput(); + +private: + wxString m_input; }; // ---------------------------------------------------------------------------- @@ -144,8 +185,10 @@ enum Exec_SyncExec = 200, Exec_AsyncExec, Exec_Shell, + Exec_OpenFile, Exec_DDEExec, Exec_Redirect, + Exec_Pipe, Exec_About = 300 }; @@ -166,9 +209,15 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec) EVT_MENU(Exec_Shell, MyFrame::OnShell) EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect) + EVT_MENU(Exec_Pipe, MyFrame::OnExecWithPipe) + + EVT_MENU(Exec_OpenFile, MyFrame::OnFileExec) + EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec) EVT_MENU(Exec_About, MyFrame::OnAbout) + + EVT_IDLE(MyFrame::OnIdle) END_EVENT_TABLE() // Create a new application object: this macro will allow wxWindows to create @@ -217,11 +266,6 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) wxApp::s_macAboutMenuItemId = Exec_About; #endif - // set the frame icon -#ifndef __WXGTK__ - SetIcon(wxICON(mondrian)); -#endif - // create a menu bar wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF); menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"), @@ -236,9 +280,15 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) _T("Launch a program and return immediately")); execMenu->Append(Exec_Shell, _T("Execute &shell command...\tCtrl-S"), _T("Launch a shell and execute a command in it")); + execMenu->AppendSeparator(); execMenu->Append(Exec_Redirect, _T("Capture command &output...\tCtrl-O"), _T("Launch a program and capture its output")); + execMenu->Append(Exec_Pipe, _T("&Pipe through command...\tCtrl-P"), + _T("Pipe a string through a filter")); + execMenu->AppendSeparator(); + execMenu->Append(Exec_OpenFile, _T("Open &file...\tCtrl-F"), + _T("Launch the command to open this kind of files")); #ifdef __WINDOWS__ execMenu->AppendSeparator(); execMenu->Append(Exec_DDEExec, _T("Execute command via &DDE...\tCtrl-D")); @@ -258,6 +308,10 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) // create the listbox in which we will show misc messages as they come m_lbox = new wxListBox(this, -1); + wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, + wxFONTWEIGHT_NORMAL); + if ( font.Ok() ) + m_lbox->SetFont(font); #if wxUSE_STATUSBAR // create a status bar just for fun (by default with 1 pane only) @@ -286,6 +340,24 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) _T("About Exec"), wxOK | wxICON_INFORMATION, this); } +void MyFrame::DoAsyncExec(const wxString& cmd) +{ + wxProcess *process = new MyProcess(this, cmd); + long pid = wxExecute(cmd, FALSE /* async */, process); + if ( !pid ) + { + wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); + + delete process; + } + else + { + wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str()); + + m_cmdLast = cmd; + } +} + void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event)) { wxString cmd = wxGetTextFromUser(_T("Enter the command: "), @@ -295,7 +367,10 @@ void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event)) if ( !cmd ) return; + wxLogStatus(_T("'%s' is running please wait..."), cmd.c_str()); + int code = wxExecute(cmd, TRUE /* sync */); + wxLogStatus(_T("Process '%s' terminated with exit code %d."), cmd.c_str(), code); m_cmdLast = cmd; @@ -310,17 +385,7 @@ void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event)) if ( !cmd ) return; - wxProcess *process = new MyProcess(this, cmd); - if ( !wxExecute(cmd, FALSE /* async */, process) ) - { - wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); - - delete process; - } - else - { - m_cmdLast = cmd; - } + DoAsyncExec(cmd); } void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event)) @@ -347,17 +412,121 @@ void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) if ( !cmd ) return; - wxProcess *process = new MyPipedProcess(this, cmd); - if ( !wxExecute(cmd, FALSE /* async */, process) ) + bool sync; + switch ( wxMessageBox(_T("Execute it synchronously?"), + _T("Exec question"), + wxYES_NO | wxCANCEL | wxICON_QUESTION, this) ) + { + case wxYES: + sync = TRUE; + break; + + case wxNO: + sync = FALSE; + break; + + default: + return; + } + + if ( sync ) + { + wxArrayString output, errors; + int code = wxExecute(cmd, output, errors); + wxLogStatus(_T("command '%s' terminated with exit code %d."), + cmd.c_str(), code); + + if ( code != -1 ) + { + ShowOutput(cmd, output, _T("Output")); + ShowOutput(cmd, errors, _T("Errors")); + } + } + else // async exec + { + MyPipedProcess *process = new MyPipedProcess(this, cmd); + if ( !wxExecute(cmd, FALSE /* async */, process) ) + { + wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); + + delete process; + } + else + { + m_running.Add(process); + } + } + + m_cmdLast = cmd; +} + +void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event)) +{ + if ( !m_cmdLast ) + m_cmdLast = _T("tr [a-z] [A-Z]"); + + wxString cmd = wxGetTextFromUser(_T("Enter the command: "), + DIALOG_TITLE, + m_cmdLast); + + if ( !cmd ) + return; + + wxString input = wxGetTextFromUser(_T("Enter the string to send to it: "), + DIALOG_TITLE); + if ( !input ) + return; + + // always execute the filter asynchronously + MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input); + int pid = wxExecute(cmd, FALSE /* async */, process); + if ( pid ) + { + wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str()); + + m_running.Add(process); + } + else { wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); delete process; } - else + + m_cmdLast = cmd; +} + +void MyFrame::OnFileExec(wxCommandEvent& event) +{ + static wxString s_filename; + + wxString filename = wxLoadFileSelector(_T("file"), _T(""), s_filename); + if ( !filename ) + return; + + s_filename = filename; + + wxString ext = filename.AfterFirst(_T('.')); + wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); + if ( !ft ) { - m_cmdLast = cmd; + wxLogError(_T("Impossible to determine the file type for extension '%s'"), + ext.c_str()); + return; + } + + wxString cmd; + bool ok = ft->GetOpenCommand(&cmd, + wxFileType::MessageParameters(filename, _T(""))); + delete ft; + if ( !ok ) + { + wxLogError(_T("Impossible to find out how to open files of extension '%s'"), + ext.c_str()); + return; } + + DoAsyncExec(cmd); } void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event)) @@ -402,6 +571,44 @@ void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event)) #endif // __WINDOWS__ } +// input polling +void MyFrame::OnIdle(wxIdleEvent& event) +{ + size_t count = m_running.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( m_running[n]->HasInput() ) + { + event.RequestMore(); + } + } +} + +void MyFrame::OnProcessTerminated(MyPipedProcess *process) +{ + m_running.Remove(process); +} + + +void MyFrame::ShowOutput(const wxString& cmd, + const wxArrayString& output, + const wxString& title) +{ + size_t count = output.GetCount(); + if ( !count ) + return; + + m_lbox->Append(wxString::Format(_T("--- %s of '%s' ---"), + title.c_str(), cmd.c_str())); + + for ( size_t n = 0; n < count; n++ ) + { + m_lbox->Append(output[n]); + } + + m_lbox->Append(_T("--- End of output ---")); +} + // ---------------------------------------------------------------------------- // MyProcess // ---------------------------------------------------------------------------- @@ -415,17 +622,73 @@ void MyProcess::OnTerminate(int pid, int status) delete this; } -void MyPipedProcess::OnTerminate(int pid, int status) +// ---------------------------------------------------------------------------- +// MyPipedProcess +// ---------------------------------------------------------------------------- + +bool MyPipedProcess::HasInput() { - // show the program output - wxListBox *lbox = m_parent->GetLogListBox(); - lbox->Append(wxString::Format(_T("--- Output of '%s' ---"), m_cmd.c_str())); + bool hasInput = FALSE; - wxTextInputStream tis(*m_in_stream); - while ( !m_in_stream->LastError() ) + wxInputStream& is = *GetInputStream(); + if ( !is.Eof() ) { - lbox->Append(tis.ReadLine()); + wxTextInputStream tis(is); + + // this assumes that the output is always line buffered + wxString msg; + msg << m_cmd << _T(" (stdout): ") << tis.ReadLine(); + + m_parent->GetLogListBox()->Append(msg); + + hasInput = TRUE; + } + + wxInputStream& es = *GetErrorStream(); + if ( !es.Eof() ) + { + wxTextInputStream tis(es); + + // this assumes that the output is always line buffered + wxString msg; + msg << m_cmd << _T(" (stderr): ") << tis.ReadLine(); + + m_parent->GetLogListBox()->Append(msg); + + hasInput = TRUE; } + return hasInput; +} + +void MyPipedProcess::OnTerminate(int pid, int status) +{ + // show the rest of the output + while ( HasInput() ) + ; + + m_parent->OnProcessTerminated(this); + MyProcess::OnTerminate(pid, status); } + +// ---------------------------------------------------------------------------- +// MyPipedProcess2 +// ---------------------------------------------------------------------------- + +bool MyPipedProcess2::HasInput() +{ + if ( !!m_input ) + { + wxTextOutputStream os(*GetOutputStream()); + os.WriteString(m_input); + + CloseOutput(); + m_input.clear(); + + // call us once again - may be we'll have output + return TRUE; + } + + return MyPipedProcess::HasInput(); +}