extcmdprogresspanel.cpp

00001 
00002 // Name:        extcmdprogresspanel.cpp
00003 // Purpose:     wxExtCmdProgressPanel
00004 // Author:      Julian Smart, Francesco Montorsi
00005 // Modified by:
00006 // Created:     15/06/2006 21:21:31
00007 // RCS-ID:      $Id: extcmdprogresspanel.cpp,v 1.9 2007/02/01 11:49:13 frm Exp $
00008 // Copyright:   (c) 2004 Francesco Montorsi
00009 // Licence:     wxWidgets license
00011 
00012 
00013 // For compilers that support precompilation, includes "wx/wx.h".
00014 #include "wx/wxprec.h"
00015 
00016 #ifdef __BORLANDC__
00017 #pragma hdrstop
00018 #endif
00019 
00020 #ifndef WX_PRECOMP
00021 #include "wx/wx.h"
00022 #endif
00023 
00024 #include <wx/txtstrm.h>
00025 #include <wx/notebook.h>
00026 #include "guipm/extcmdprogresspanel.h"
00027 
00028 
00029 // ----------------------------------------------------------------------------
00030 // wxExtCmdProgressPanel
00031 // ----------------------------------------------------------------------------
00032 
00033 IMPLEMENT_DYNAMIC_CLASS( wxExtCmdProgressPanel, wxPanel )
00034 DEFINE_EVENT_TYPE(wxEVT_COMMAND_PROGRESS_FAILED)
00035 DEFINE_EVENT_TYPE(wxEVT_COMMAND_PROGRESS_END)
00036 BEGIN_EVENT_TABLE( wxExtCmdProgressPanel, wxPanel )
00037     EVT_IDLE( wxExtCmdProgressPanel::OnIdle )
00038     EVT_END_PROCESS( ID_EXTCMD_PROCESS, wxExtCmdProgressPanel::OnProcessTerminate )
00039     EVT_UPDATE_UI( wxID_ANY, wxExtCmdProgressPanel::OnUpdateUI )
00040 END_EVENT_TABLE()
00041 
00042 
00043 wxExtCmdProgressPanel::wxExtCmdProgressPanel( )
00044 {
00045 }
00046 
00047 wxExtCmdProgressPanel::wxExtCmdProgressPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString &name )
00048 {
00049     Create(parent, id, pos, size, style, name);
00050 }
00051 
00052 bool wxExtCmdProgressPanel::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString &name )
00053 {
00054     m_currProcess = NULL;
00055     m_pCommandList = NULL;
00056     m_pOutput = NULL;
00057     m_pGauge = NULL;
00058     m_stage = wxPBSS_INVALID;
00059     m_pid = 0;
00060 
00061     wxPanel::Create( parent, id, pos, size, style, name );
00062 
00063     CreateControls();
00064     GetSizer()->Fit(this);
00065     GetSizer()->SetSizeHints(this);
00066     Centre();
00067 
00068     return true;
00069 }
00070 
00071 void wxExtCmdProgressPanel::CreateControls()
00072 {
00073 
00075     wxExtCmdProgressPanel* itemProgressPanel1 = this;
00076 
00077     wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
00078     itemProgressPanel1->SetSizer(itemBoxSizer2);
00079 
00080     wxStaticText* itemStaticText3 = new wxStaticText( itemProgressPanel1, wxID_STATIC, _("Commands:"), wxDefaultPosition, wxDefaultSize, 0 );
00081     itemBoxSizer2->Add(itemStaticText3, 0, wxALIGN_LEFT|wxALL|wxADJUST_MINSIZE, 5);
00082 
00083     wxString* m_pCommandListStrings = NULL;
00084     m_pCommandList = new wxListBox( itemProgressPanel1, ID_EXTCMD_COMMANDS, wxDefaultPosition, wxDefaultSize, 0, m_pCommandListStrings, wxLB_SINGLE );
00085     itemBoxSizer2->Add(m_pCommandList, 2, wxGROW|wxALL, 5);
00086 
00087     wxStaticText* itemStaticText5 = new wxStaticText( itemProgressPanel1, wxID_STATIC, _("Output:"), wxDefaultPosition, wxDefaultSize, 0 );
00088     itemBoxSizer2->Add(itemStaticText5, 0, wxALIGN_LEFT|wxALL|wxADJUST_MINSIZE, 5);
00089 
00090     m_pGauge = new wxGauge( itemProgressPanel1, ID_EXTCMD_GAUGE, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL );
00091     m_pGauge->SetValue(0);
00092     itemBoxSizer2->Add(m_pGauge, 0, wxGROW|wxALL, 5);
00093 
00094     wxNotebook* itemNotebook7 = new wxNotebook( itemProgressPanel1, ID_EXTCMD_NOTEBOOK, wxDefaultPosition, wxDefaultSize, wxNB_TOP );
00095 
00096     wxPanel* itemPanel8 = new wxPanel( itemNotebook7, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
00097     wxBoxSizer* itemBoxSizer9 = new wxBoxSizer(wxVERTICAL);
00098     itemPanel8->SetSizer(itemBoxSizer9);
00099 
00100     m_pOutput = new wxTextCtrl( itemPanel8, ID_EXTCMD_OUTPUT, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE );
00101     itemBoxSizer9->Add(m_pOutput, 1, wxGROW|wxALL, 5);
00102 
00103     itemNotebook7->AddPage(itemPanel8, _("Output"));
00104 
00105     wxPanel* itemPanel11 = new wxPanel( itemNotebook7, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
00106     wxBoxSizer* itemBoxSizer12 = new wxBoxSizer(wxVERTICAL);
00107     itemPanel11->SetSizer(itemBoxSizer12);
00108 
00109     m_pOutputErr = new wxTextCtrl( itemPanel11, ID_EXTCMD_OUTPUTERR, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE );
00110     itemBoxSizer12->Add(m_pOutputErr, 1, wxGROW|wxALL, 5);
00111 
00112     itemNotebook7->AddPage(itemPanel11, _("Errors/Warnings"));
00113 
00114     itemBoxSizer2->Add(itemNotebook7, 5, wxGROW|wxALL, 5);
00115 
00117 }
00118 
00119 void wxExtCmdProgressPanel::SelectCurrProcess()
00120 {
00121     wxASSERT(m_nCurrProcess >= 0);
00122 
00123     // prefix the current process string for a nice effect
00124     m_pCommandList->SetString(m_nCurrProcess,
00125         ID_EXTCMD_CURRPROCESS_PREFIX +
00126         m_pCommandList->GetString(m_nCurrProcess));
00127 
00128     m_pCommandList->SetSelection(m_nCurrProcess);
00129 }
00130 
00131 void wxExtCmdProgressPanel::DeselectCurrProcess()
00132 {
00133     wxASSERT(m_nCurrProcess >= 0);
00134 
00135     // de-'select' the previous command
00136     wxString str = m_pCommandList->GetString(m_nCurrProcess);
00137     wxASSERT(str.StartsWith(ID_EXTCMD_CURRPROCESS_PREFIX));
00138     m_pCommandList->SetString(m_nCurrProcess,
00139         str.Right(str.Len() - wxString(ID_EXTCMD_CURRPROCESS_PREFIX).Len()));
00140 }
00141 
00142 void wxExtCmdProgressPanel::OnProcessStart()
00143 {
00144     SelectCurrProcess();
00145 
00146     m_pGauge->SetValue((m_nCurrProcess+1) * 100 / m_cmd.GetCount());
00147 }
00148 
00149 wxString wxExtCmdProgressPanel::GetLogData() const
00150 {
00151     wxString ret;
00152 
00153     if (m_stage == wxPBSS_INVALID)
00154         return wxEmptyString;
00155 
00156     ret = wxString::Format(
00157         wxT(" ===== %s LOG FOR %s - %s ===== \n\n"),
00158         wxPackageBuildSystemStage2String(m_stage).MakeUpper().c_str(), 
00159         m_pkg.GetName().c_str(),
00160         m_start.Format().c_str());
00161 
00162     for (size_t i=0; i< m_cmd.GetCount(); i++)
00163         ret += GetCmdString(i) + wxString(wxT(' '), 15) + 
00164                wxT(" [in path: ") + GetCmdPath(i) + wxT("]\n");
00165 
00166     ret += wxT("\n\n ===> Output:\n");
00167     ret += m_pOutput->GetValue();
00168     ret += wxT("\n\n ===> Errors:\n");
00169     ret += m_pOutputErr->GetValue();
00170 
00171     return ret;
00172 }
00173 wxString wxExtCmdProgressPanel::GetLogLabel() const
00174 {
00175     return wxString::Format(wxT("Log for %s of %s %s"),
00176                             wxPackageBuildSystemStage2String(m_stage).MakeUpper().c_str(),
00177                             m_pkg.GetName().c_str(),
00178                             m_pkg.GetVersion().GetAsString().c_str());
00179 }
00180 
00181 void wxExtCmdProgressPanel::Start()
00182 {
00183     wxASSERT(!m_timerIdleWakeUp.IsRunning());
00184 
00185     m_pOutput->Clear();
00186     m_pOutputErr->Clear();
00187     m_nCurrProcess = -1;
00188     m_timerIdleWakeUp.Start(100);
00189     m_start = wxDateTime::Now();
00190 }
00191 
00192 void wxExtCmdProgressPanel::Stop()
00193 {
00194     //  wxASSERT(m_timerIdleWakeUp.IsRunning());    it could have been already stopped
00195     m_timerIdleWakeUp.Stop();
00196 
00197     // ask the current process to terminate
00198     if (m_pid != 0)
00199         m_currProcess->Kill(m_pid, wxSIGTERM);
00200 }
00201 
00202 void wxExtCmdProgressPanel::ClearControls()
00203 {
00204     // reset the controls (gauge is reset in OnUpdateUI)
00205     m_pCommandList->Clear();
00206     m_pOutput->Clear();
00207     m_pOutputErr->Clear();
00208 }
00209 
00210 void wxExtCmdProgressPanel::SetPackage(const wxPackage &pkg)
00211 {
00212     m_pkg=pkg;
00213 
00214     // cache the substituted array of commands for this package:
00215     UpdateCachedCommands();
00216 
00217     // add the commands to our listbox:
00218     m_pCommandList->Clear();
00219     for (size_t i=0; i<m_cmd.GetCount(); i++)
00220         m_pCommandList->Append(m_cmd[i]);
00221 }
00222 
00223 void wxExtCmdProgressPanel::UpdateCachedCommands()
00224 {
00225     m_cmd = m_pkg.GetSubstCmdForStage(m_stage, wxPKGCMD_ONLY_CHANGED);
00226 
00227     // now filter out the invalid commands for current package:
00228     m_cmd = m_cmd.GetValidCommandsFor(m_pkg);
00229 }
00230 
00231 wxString wxExtCmdProgressPanel::GetCmdString(size_t n) const
00232 { 
00233     const wxPackageCommand &cmd = m_cmd[n]; 
00234     return cmd.GetProgram() + wxT(" ") + cmd.GetProgramArguments();
00235 }
00236 
00237 wxString wxExtCmdProgressPanel::GetCmdPath(size_t n) const
00238 {
00239     // build the path where to exec the command
00240     wxFileName path = wxFileName::DirName(m_cmd[n].GetWorkingPath(), wxPATH_UNIX);
00241 
00242     wxString workDir(m_pkg.GetDecompressionPath());
00243     if (!path.MakeAbsolute(workDir) || !path.DirExists())
00244         path = wxFileName::DirName(workDir);
00245 
00246     return path.GetPath();
00247 }
00248 
00249 
00250 
00251 // ----------------------------------------------------------------------------
00252 // wxExtCmdProgressPanel - event handlers
00253 // ----------------------------------------------------------------------------
00254 
00255 void wxExtCmdProgressPanel::OnTimer(wxTimerEvent& WXUNUSED(event))
00256 {
00257     // force the system to send idle events
00258     wxWakeUpIdle();
00259 }
00260 
00261 void wxExtCmdProgressPanel::OnIdle(wxIdleEvent &ev)
00262 {
00263     if (!m_timerIdleWakeUp.IsRunning())
00264         return;
00265 
00266     if (m_currProcess)
00267     {
00268         wxInputStream *stream = NULL;
00269         wxTextCtrl *output = NULL;
00270 
00271         // there is a process already running...
00272         if (m_currProcess->IsInputAvailable())
00273         {
00274             stream = m_currProcess->GetInputStream();
00275             output = m_pOutput;
00276         }
00277         else if (m_currProcess->IsErrorAvailable())
00278         {
00279             stream = m_currProcess->GetErrorStream();
00280             output = m_pOutputErr;
00281         }
00282 
00283         if (stream)
00284         {
00285             ev.RequestMore();
00286             wxTextInputStream tis(*stream);
00287 
00288 #if 0
00289             // this assumes that the output is always line buffered
00290             wxString msg = tis.ReadLine() + wxT("\n");
00291 #else
00292             static char buffer[4096];
00293             buffer[stream->Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = _T('\0');
00294             wxString msg(buffer, wxConvUTF8);
00295             msg = msg.BeforeLast(wxT('\n'));
00296 #endif
00297 
00298             output->AppendText(msg);
00299         }
00300     }
00301     else if (++m_nCurrProcess >= (int)m_cmd.GetCount())
00302     {
00303         // no more commands to run !
00304         wxCommandEvent ev(wxEVT_COMMAND_PROGRESS_END, GetId());
00305         ev.SetInt(m_stage);
00306         ev.SetExtraLong(IsSuccessful());
00307         ev.SetString(m_pkg.GetName());
00308 
00309         GetEventHandler()->AddPendingEvent(ev);
00310     }
00311     else
00312     {
00313         // there's a command to run!
00314 
00315         // get next command to execute
00316         const wxPackageCommand &cmd = m_cmd[m_nCurrProcess];
00317 
00318         // update 'selected' command in the list box
00319         OnProcessStart();       // this must be called *before* wxExecute call
00320 
00321         // update this process' env var so that the
00322         // child process we're going to launch will inherit their values
00323         m_pkg.GetCompilerSettings().UpdateEnvVars();
00324 
00325         // set our current directory (previous commands could have changed it)
00326         wxString path = GetCmdPath(m_nCurrProcess);
00327         if (!wxSetWorkingDirectory(path))
00328         {
00329             wxLogError(_T("Cannot set the current working directory to '%s'."),
00330                        path.c_str());
00331             return;
00332         }
00333 
00334         m_currProcess = new wxProcess(this, ID_EXTCMD_PROCESS);
00335         m_currProcess->Redirect();
00336 
00337         wxString tolaunch = cmd.GetProgram();
00338         if (!tolaunch.IsEmpty())
00339         {
00340             wxString final = GetCmdString(m_nCurrProcess);
00341             wxLogDebug(wxT("Launching command '%s' in dir '%s'"), 
00342                        final.c_str(), wxGetCwd().c_str());
00343 
00344             // launch it !
00345             m_pid = wxExecute(final, wxEXEC_ASYNC|wxEXEC_MAKE_GROUP_LEADER, m_currProcess);
00346             if ( m_pid == 0 )
00347             {
00348                 wxLogError(_T("Execution of '%s' failed."), cmd.GetCommand().c_str());
00349                 wxDELETE(m_currProcess);
00350                 DeselectCurrProcess();
00351             }
00352         }
00353         else     /* FIXME */
00354         {
00355             wxArrayString arr(m_pkg.GetCompilerSettings().GetCompilerPaths(wxPCPT_BIN));
00356             if (arr.GetCount() > 0)
00357             {
00358                 wxString err;
00359                 err.Printf(_("Cannot find the '%s' program in the compiler paths currently in use:\n\n"),
00360                            cmd.GetProgram().c_str());
00361                 for (size_t i=0; i < arr.GetCount(); i++)
00362                     err += wxT(" => ") + arr[i] + wxT("\n");
00363                 err += _("\n\nPlease configure appropriately the compiler paths in the 'Settings' dialog.");
00364 
00365                 wxLogError(err);
00366             }
00367             else
00368             {
00369                 wxLogError(_("The compiler paths for the '%s' format are empty! Cannot find the '%s' program.\nPlease configure appropriately the compiler paths in the 'Settings' dialog."),
00370                            wxPackageCompilerFormat2String(m_pkg.GetCompilerSettings().GetSelFormat()).c_str(),
00371                            cmd.GetProgram().c_str());
00372             }
00373 
00374             wxDELETE(m_currProcess);
00375             DeselectCurrProcess();
00376         }
00377     }
00378 }
00379 
00380 void wxExtCmdProgressPanel::OnProcessTerminate(wxProcessEvent &ev)
00381 {
00382     wxIdleEvent fake;
00383     while (m_currProcess->IsInputAvailable() ||
00384            m_currProcess->IsErrorAvailable())
00385         OnIdle(fake);   // show the rest of the output
00386 
00387     // save exit code
00388     m_nExitCode = ev.GetExitCode();
00389     wxDELETE(m_currProcess);
00390     DeselectCurrProcess();
00391 
00392     // if this is the last process, reset the gauge
00393     if (m_nCurrProcess == (int)m_cmd.GetCount() - 1)
00394         m_pGauge->SetValue(0);
00395 }
00396 
00397 void wxExtCmdProgressPanel::OnUpdateUI(wxUpdateUIEvent &WXUNUSED(ev))
00398 {
00399     if (!IsProcessing())
00400         m_pGauge->SetValue(0);      // reset the gauge
00401 }
00402 

Generated on Thu Feb 1 22:14:30 2007 for wxWidgets Package Manager by  doxygen 1.5.1-p1