X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9a83f860948059b0273b5cc6d9e43fadad3ebfca..f155075229d771430f0793700f5048ad4be00e9d:/samples/exec/exec.cpp diff --git a/samples/exec/exec.cpp b/samples/exec/exec.cpp index ab63144a8e..d72c89a7ad 100644 --- a/samples/exec/exec.cpp +++ b/samples/exec/exec.cpp @@ -43,6 +43,8 @@ #include "wx/choicdlg.h" #include "wx/button.h" + #include "wx/checkbox.h" + #include "wx/stattext.h" #include "wx/textctrl.h" #include "wx/listbox.h" @@ -53,6 +55,7 @@ #include "wx/numdlg.h" #include "wx/textdlg.h" #include "wx/ffile.h" +#include "wx/scopedptr.h" #include "wx/stopwatch.h" #include "wx/process.h" @@ -63,6 +66,10 @@ #include "wx/dde.h" #endif // __WINDOWS__ +#ifndef wxHAS_IMAGES_IN_RESOURCES + #include "../sample.xpm" +#endif + // ---------------------------------------------------------------------------- // the usual application and main frame classes // ---------------------------------------------------------------------------- @@ -106,7 +113,6 @@ public: void OnEndBusyCursor(wxCommandEvent& event); void OnSyncExec(wxCommandEvent& event); - void OnSyncNoEventsExec(wxCommandEvent& event); void OnAsyncExec(wxCommandEvent& event); void OnShell(wxCommandEvent& event); void OnExecWithRedirect(wxCommandEvent& event); @@ -117,6 +123,7 @@ public: void OnFileExec(wxCommandEvent& event); void OnFileLaunch(wxCommandEvent& event); void OnOpenURL(wxCommandEvent& event); + void OnShowCommandForExt(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); @@ -139,6 +146,8 @@ private: const wxArrayString& output, const wxString& title); + int GetExecFlags() const; + void DoAsyncExec(const wxString& cmd); void AddAsyncProcess(MyProcess *process) { m_allAsync.push_back(process); } @@ -305,24 +314,27 @@ enum Exec_TimerBg, // menu items - Exec_Quit = 100, - Exec_Kill, + Exec_Kill = 100, Exec_ClearLog, Exec_BeginBusyCursor, Exec_EndBusyCursor, Exec_SyncExec = 200, - Exec_SyncNoEventsExec, Exec_AsyncExec, Exec_Shell, Exec_POpen, Exec_OpenFile, + Exec_ShowCommandForExt, Exec_LaunchFile, Exec_OpenURL, Exec_DDEExec, Exec_DDERequest, Exec_Redirect, Exec_Pipe, + Exec_Flags_HideConsole, + Exec_Flags_ShowConsole, + Exec_Flags_NoEvents, Exec_About = wxID_ABOUT, + Exec_Quit = wxID_EXIT, // control ids Exec_Btn_Send = 1000, @@ -348,7 +360,6 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Exec_EndBusyCursor, MyFrame::OnEndBusyCursor) EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec) - EVT_MENU(Exec_SyncNoEventsExec, MyFrame::OnSyncNoEventsExec) EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec) EVT_MENU(Exec_Shell, MyFrame::OnShell) EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect) @@ -357,6 +368,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Exec_POpen, MyFrame::OnPOpen) EVT_MENU(Exec_OpenFile, MyFrame::OnFileExec) + EVT_MENU(Exec_ShowCommandForExt, MyFrame::OnShowCommandForExt) EVT_MENU(Exec_LaunchFile, MyFrame::OnFileLaunch) EVT_MENU(Exec_OpenURL, MyFrame::OnOpenURL) @@ -411,9 +423,8 @@ bool MyApp::OnInit() MyFrame *frame = new MyFrame(wxT("Exec wxWidgets sample"), wxDefaultPosition, wxSize(500, 140)); - // Show it and tell the application that it's our main window + // Show it frame->Show(true); - SetTopWindow(frame); // success: wxApp::OnRun() will be called which will enter the main message // loop and the application will run. If we returned false here, the @@ -435,6 +446,8 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) m_timerIdleWakeUp(this, Exec_TimerIdle), m_timerBg(this, Exec_TimerBg) { + SetIcon(wxICON(sample)); + m_pidLast = 0; #ifdef __WXMAC__ @@ -448,19 +461,35 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) menuFile->Append(Exec_Kill, wxT("&Kill process...\tCtrl-K"), wxT("Kill a process by PID")); menuFile->AppendSeparator(); - menuFile->Append(Exec_ClearLog, wxT("&Clear log\tCtrl-L"), - wxT("Clear the log window")); + menuFile->Append(Exec_OpenFile, wxT("Open &file...\tCtrl-F"), + wxT("Launch the command to open this kind of files")); + menuFile->Append(Exec_ShowCommandForExt, + "Show association for extension...\tShift-Ctrl-A", + "Show the command associated with the given extension"); + menuFile->Append(Exec_LaunchFile, wxT("La&unch file...\tShift-Ctrl-F"), + wxT("Launch the default application associated with the file")); + menuFile->Append(Exec_OpenURL, wxT("Open &URL...\tCtrl-U"), + wxT("Launch the default browser with the given URL")); menuFile->AppendSeparator(); menuFile->Append(Exec_BeginBusyCursor, wxT("Show &busy cursor\tCtrl-C")); menuFile->Append(Exec_EndBusyCursor, wxT("Show &normal cursor\tShift-Ctrl-C")); menuFile->AppendSeparator(); + menuFile->Append(Exec_ClearLog, wxT("&Clear log\tCtrl-L"), + wxT("Clear the log window")); + menuFile->AppendSeparator(); menuFile->Append(Exec_Quit, wxT("E&xit\tAlt-X"), wxT("Quit this program")); + wxMenu *flagsMenu = new wxMenu; + flagsMenu->AppendCheckItem(Exec_Flags_HideConsole, "Always &hide console"); + flagsMenu->AppendCheckItem(Exec_Flags_ShowConsole, "Always &show console"); + flagsMenu->AppendCheckItem(Exec_Flags_NoEvents, "Disable &events", + "This flag is valid for sync execution only"); + wxMenu *execMenu = new wxMenu; + execMenu->AppendSubMenu(flagsMenu, "Execution flags"); + execMenu->AppendSeparator(); execMenu->Append(Exec_SyncExec, wxT("Sync &execution...\tCtrl-E"), wxT("Launch a program and return when it terminates")); - execMenu->Append(Exec_SyncNoEventsExec, wxT("Sync execution and &block...\tCtrl-B"), - wxT("Launch a program and block until it terminates")); execMenu->Append(Exec_AsyncExec, wxT("&Async execution...\tCtrl-A"), wxT("Launch a program and return immediately")); execMenu->Append(Exec_Shell, wxT("Execute &shell command...\tCtrl-S"), @@ -473,13 +502,6 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) execMenu->Append(Exec_POpen, wxT("&Open a pipe to a command...\tCtrl-P"), wxT("Open a pipe to and from another program")); - execMenu->AppendSeparator(); - execMenu->Append(Exec_OpenFile, wxT("Open &file...\tCtrl-F"), - wxT("Launch the command to open this kind of files")); - execMenu->Append(Exec_LaunchFile, wxT("La&unch file...\tShift-Ctrl-F"), - wxT("Launch the default application associated with the file")); - execMenu->Append(Exec_OpenURL, wxT("Open &URL...\tCtrl-U"), - wxT("Launch the default browser with the given URL")); #ifdef __WINDOWS__ execMenu->AppendSeparator(); execMenu->Append(Exec_DDEExec, wxT("Execute command via &DDE...\tCtrl-D")); @@ -487,7 +509,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) #endif wxMenu *helpMenu = new wxMenu(wxEmptyString, wxMENU_TEAROFF); - helpMenu->Append(Exec_About, wxT("&About...\tF1"), wxT("Show about dialog")); + helpMenu->Append(Exec_About, wxT("&About\tF1"), wxT("Show about dialog")); // now append the freshly created menu to the menu bar... wxMenuBar *menuBar = new wxMenuBar(); @@ -502,7 +524,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) m_lbox = new wxListBox(this, wxID_ANY); wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); - if ( font.Ok() ) + if ( font.IsOk() ) m_lbox->SetFont(font); #if wxUSE_STATUSBAR @@ -571,6 +593,8 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event)) return; } + m_pidLast = pid; + static const wxString signalNames[] = { wxT("Just test (SIGNONE)"), @@ -591,9 +615,11 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event)) wxT("Terminate (SIGTERM)"), }; + static int s_sigLast = wxSIGNONE; int sig = wxGetSingleChoiceIndex(wxT("How to kill the process?"), wxT("Exec question"), WXSIZEOF(signalNames), signalNames, + s_sigLast, this); switch ( sig ) { @@ -624,8 +650,11 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event)) break; } - if ( sig == 0 ) + s_sigLast = sig; + + if ( sig == wxSIGNONE ) { + // This simply calls Kill(wxSIGNONE) but using it is more convenient. if ( wxProcess::Exists(pid) ) { wxLogStatus(wxT("Process %ld is running."), pid); @@ -659,14 +688,171 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event)) } } +// ---------------------------------------------------------------------------- +// execution options dialog +// ---------------------------------------------------------------------------- + +enum ExecQueryDialogID +{ + TEXT_EXECUTABLE, + TEXT_CWD, + TEXT_ENVIRONMENT +}; + +class ExecQueryDialog : public wxDialog +{ +public: + ExecQueryDialog(const wxString& cmd); + + wxString GetExecutable() const + { + return m_executable->GetValue(); + } + + wxString GetWorkDir() const + { + return m_useCWD->GetValue() ? m_cwdtext->GetValue() : wxString(); + } + + void GetEnvironment(wxEnvVariableHashMap& env); + +private: + void OnUpdateWorkingDirectoryUI(wxUpdateUIEvent& event) + { + event.Enable(m_useCWD->GetValue()); + } + + void OnUpdateEnvironmentUI(wxUpdateUIEvent& event) + { + event.Enable(m_useEnv->GetValue()); + } + + wxTextCtrl* m_executable; + wxTextCtrl* m_cwdtext; + wxTextCtrl* m_envtext; + wxCheckBox* m_useCWD; + wxCheckBox* m_useEnv; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(ExecQueryDialog, wxDialog) + EVT_UPDATE_UI(TEXT_CWD, ExecQueryDialog::OnUpdateWorkingDirectoryUI) + EVT_UPDATE_UI(TEXT_ENVIRONMENT, ExecQueryDialog::OnUpdateEnvironmentUI) +END_EVENT_TABLE() + +ExecQueryDialog::ExecQueryDialog(const wxString& cmd) + : wxDialog(NULL, wxID_ANY, DIALOG_TITLE, + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + wxSizer* globalSizer = new wxBoxSizer(wxVERTICAL); + + m_executable = new wxTextCtrl(this, TEXT_EXECUTABLE, wxString()); + m_cwdtext = new wxTextCtrl(this, TEXT_CWD, wxString()); + m_envtext = new wxTextCtrl(this, TEXT_ENVIRONMENT, wxString(), + wxDefaultPosition, wxSize(300, 200), + wxTE_MULTILINE|wxHSCROLL); + + const wxSizerFlags flagsExpand = wxSizerFlags().Expand().Border(); + globalSizer->Add(new wxStaticText(this, wxID_ANY, "Enter the command: "), + flagsExpand); + globalSizer->Add(m_executable, flagsExpand); + + m_useCWD = new wxCheckBox(this, wxID_ANY, "Working directory: "); + globalSizer->Add(m_useCWD, flagsExpand); + globalSizer->Add(m_cwdtext, flagsExpand); + + m_useEnv = new wxCheckBox(this, wxID_ANY, "Environment: "); + globalSizer->Add(m_useEnv, flagsExpand); + globalSizer->Add(m_envtext, wxSizerFlags(flagsExpand).Proportion(1)); + + globalSizer->Add(CreateStdDialogButtonSizer(wxOK|wxCANCEL), flagsExpand); + SetSizerAndFit(globalSizer); + + + m_executable->SetValue(cmd); + m_cwdtext->SetValue(wxGetCwd()); + wxEnvVariableHashMap env; + if ( wxGetEnvMap(&env) ) + { + for ( wxEnvVariableHashMap::iterator it = env.begin(); + it != env.end(); + ++it ) + { + m_envtext->AppendText(it->first + '=' + it->second + '\n'); + } + } + m_useCWD->SetValue(false); + m_useEnv->SetValue(false); +} + +void ExecQueryDialog::GetEnvironment(wxEnvVariableHashMap& env) +{ + env.clear(); + if ( m_useEnv->GetValue() ) + { + wxString name, + value; + + const int nb = m_envtext->GetNumberOfLines(); + for ( int l = 0; l < nb; l++ ) + { + const wxString line = m_envtext->GetLineText(l).Trim(); + + if ( !line.empty() ) + { + name = line.BeforeFirst('=', &value); + if ( name.empty() ) + { + wxLogWarning("Skipping invalid environment line \"%s\".", line); + continue; + } + + env[name] = value; + } + } + } +} + +static bool QueryExec(wxString& cmd, wxExecuteEnv& env) +{ + ExecQueryDialog dialog(cmd); + + if ( dialog.ShowModal() != wxID_OK ) + return false; + + cmd = dialog.GetExecutable(); + env.cwd = dialog.GetWorkDir(); + dialog.GetEnvironment(env.env); + + return true; +} + // ---------------------------------------------------------------------------- // event handlers: exec menu // ---------------------------------------------------------------------------- +int MyFrame::GetExecFlags() const +{ + wxMenuBar* const mbar = GetMenuBar(); + + int flags = 0; + + if ( mbar->IsChecked(Exec_Flags_HideConsole) ) + flags |= wxEXEC_HIDE_CONSOLE; + if ( mbar->IsChecked(Exec_Flags_ShowConsole) ) + flags |= wxEXEC_SHOW_CONSOLE; + if ( mbar->IsChecked(Exec_Flags_NoEvents) ) + flags |= wxEXEC_NOEVENTS; + + return flags; +} + void MyFrame::DoAsyncExec(const wxString& cmd) { MyProcess * const process = new MyProcess(this, cmd); - m_pidLast = wxExecute(cmd, wxEXEC_ASYNC, process); + m_pidLast = wxExecute(cmd, wxEXEC_ASYNC | GetExecFlags(), process); if ( !m_pidLast ) { wxLogError(wxT("Execution of '%s' failed."), cmd.c_str()); @@ -687,35 +873,14 @@ void MyFrame::DoAsyncExec(const wxString& cmd) void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event)) { - wxString cmd = wxGetTextFromUser(wxT("Enter the command: "), - DIALOG_TITLE, - m_cmdLast); - - if ( !cmd ) - return; - - wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() ); - - int code = wxExecute(cmd, wxEXEC_SYNC); - - wxLogStatus(wxT("Process '%s' terminated with exit code %d."), - cmd.c_str(), code); - - m_cmdLast = cmd; -} - -void MyFrame::OnSyncNoEventsExec(wxCommandEvent& WXUNUSED(event)) -{ - wxString cmd = wxGetTextFromUser(wxT("Enter the command: "), - DIALOG_TITLE, - m_cmdLast); - - if ( !cmd ) + wxString cmd; + wxExecuteEnv env; + if ( !QueryExec(cmd, env) ) return; wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() ); - int code = wxExecute(cmd, wxEXEC_BLOCK); + int code = wxExecute(cmd, wxEXEC_SYNC | GetExecFlags(), NULL, &env); wxLogStatus(wxT("Process '%s' terminated with exit code %d."), cmd.c_str(), code); @@ -940,6 +1105,41 @@ void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event)) DoAsyncExec(cmd); } +void MyFrame::OnShowCommandForExt(wxCommandEvent& WXUNUSED(event)) +{ + static wxString s_ext; + + wxString ext = wxGetTextFromUser + ( + "Enter the extension without leading dot", + "Exec sample", + s_ext, + this + ); + if ( ext.empty() ) + return; + + s_ext = ext; + + wxScopedPtr + ft(wxTheMimeTypesManager->GetFileTypeFromExtension(ext)); + if ( !ft ) + { + wxLogError("Information for extension \"%s\" not found", ext); + return; + } + + const wxString cmd = ft->GetOpenCommand("file." + ext); + if ( cmd.empty() ) + { + wxLogWarning("Open command for extension \"%s\" not defined.", ext); + return; + } + + wxLogMessage("Open command for files of extension \"%s\" is\n%s", + ext, cmd); +} + void MyFrame::OnFileLaunch(wxCommandEvent& WXUNUSED(event)) { if ( !AskUserForFileName() ) @@ -1323,8 +1523,8 @@ void MyPipeFrame::DoGetFromStream(wxTextCtrl *text, wxInputStream& in) { while ( in.CanRead() ) { - wxChar buffer[4096]; - buffer[in.Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = wxT('\0'); + char buffer[4096]; + buffer[in.Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = '\0'; text->AppendText(buffer); } @@ -1370,8 +1570,7 @@ void MyPipeFrame::OnProcessTerm(wxProcessEvent& WXUNUSED(event)) { DoGet(); - delete m_process; - m_process = NULL; + wxDELETE(m_process); wxLogWarning(wxT("The other process has terminated, closing"));