Batch.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00027 #include "Batch.h"
00028 #include <wx/stdpaths.h>
00029 
00030 BEGIN_EVENT_TABLE(Batch, wxFrame)
00031     EVT_END_PROCESS(-1, Batch::OnProcessTerminate)
00032 END_EVENT_TABLE()
00033 
00034 #if _WINDOWS && defined Hugin_shared
00035 DEFINE_LOCAL_EVENT_TYPE(EVT_BATCH_FAILED)
00036 DEFINE_LOCAL_EVENT_TYPE(EVT_INFORMATION)
00037 DEFINE_LOCAL_EVENT_TYPE(EVT_UPDATE_PARENT)
00038 #else
00039 DEFINE_EVENT_TYPE(EVT_BATCH_FAILED)
00040 DEFINE_EVENT_TYPE(EVT_INFORMATION)
00041 DEFINE_EVENT_TYPE(EVT_UPDATE_PARENT)
00042 #endif
00043 
00044 Batch::Batch(wxFrame* parent, wxString path, bool bgui) : wxFrame(parent,wxID_ANY,_T("Batch"))
00045 {
00046     //default flag settings
00047     parallel = false;
00048     deleteFiles = false;
00049     shutdown = false;
00050     overwrite = true;
00051     verbose = false;
00052     autoremove = false;
00053     autostitch = false;
00054     saveLog = false;
00055     gui = bgui;
00056     m_cancelled = false;
00057     m_paused = false;
00058     m_running = false;
00059     m_clearedInProgress = false;
00060     m_lastFile = wxT("");
00061 
00062     // Required to access the preferences of hugin
00063     //SetAppName(wxT("hugin"));
00064 
00065     // setup the environment for the different operating systems
00066     wxConfigBase* config=wxConfigBase::Get();
00067 #if defined __WXMSW__
00068     wxString huginExeDir = getExePath(path);
00069 
00070     wxString huginRoot;
00071     wxFileName::SplitPath(huginExeDir, &huginRoot, NULL, NULL);
00072 
00073     progs = getPTProgramsConfig(huginExeDir, config);
00074     progsAss = getAssistantProgramsConfig(huginExeDir, config);
00075 #else
00076     // add the locale directory specified during configure
00077     progs = getPTProgramsConfig(wxT(""), config);
00078     progsAss = getAssistantProgramsConfig(wxT(""), config);
00079 #endif
00080 
00081 }
00082 
00083 void Batch::AddAppToBatch(wxString app)
00084 {
00085     Project* newApp = new Project(app);
00086     m_projList.Add(newApp);
00087 }
00088 
00089 void Batch::AddProjectToBatch(wxString projectFile, wxString outputFile,Project::Target target)
00090 {
00091     wxFileName projectName(projectFile);
00092     wxFileName outName(outputFile);
00093     projectName.Normalize();
00094     outName.Normalize();
00095 
00096     if(outputFile.Cmp(_T(""))!=0 || target==Project::DETECTING)
00097     {
00098         Project* proj = new Project(projectName.GetFullPath(),outName.GetFullPath(),target);
00099         m_projList.Add(proj);
00100     }
00101     else
00102     {
00103         //on output set as "", it defaults to same path and name as project file
00104         Project* proj = new Project(projectName.GetFullPath(),wxT(""));
00105         m_projList.Add(proj);
00106     }
00107 }
00108 
00109 bool Batch::AllDone()
00110 {
00111     for(unsigned int i=0; i<m_projList.GetCount(); i++)
00112     {
00113         if(m_projList.Item(i).status==Project::WAITING ||
00114                 m_projList.Item(i).status==Project::RUNNING ||
00115                 m_projList.Item(i).status==Project::PAUSED)
00116         {
00117             return false;
00118         }
00119     }
00120     return true;
00121 }
00122 
00123 void Batch::AppendBatchFile(wxString file)
00124 {
00125     wxFileName aFile(file);
00126     if(aFile.FileExists())
00127     {
00128         m_lastFile = file;
00129         aFile.GetTimes(NULL,NULL,&m_lastmod);
00130         wxFileInputStream fileStream(file);
00131         wxString projectName = _T("");
00132 #ifdef __WXMSW__
00133         wxTextInputStream textStream(fileStream, wxT(" \t"), wxConvLocal);
00134 #else
00135         wxTextInputStream textStream(fileStream);
00136 #endif
00137 
00138         //TO-DO: batch file error checking?
00139         //first line in file is idGenerator, we save it a temp variable, cause it gets set when adding projects
00140         long idGenTemp = 1;
00141         textStream.ReadLine().ToLong(&idGenTemp);
00142         //then for each project: project path, prefix, id, status, skip
00143         while((projectName = textStream.ReadLine()).Cmp(wxT(""))!=0)
00144         {
00145             //we add project to internal list
00146             wxString line=textStream.ReadLine();
00147             if(line.IsEmpty())
00148             {
00149                 AddProjectToBatch(projectName,wxT(""),Project::DETECTING);
00150             }
00151             else
00152             {
00153                 AddProjectToBatch(projectName,line);
00154             };
00155             textStream.ReadLine().ToLong(&m_projList.Last().id);
00156             long status;
00157             textStream.ReadLine().ToLong(&status);
00158             //if status was RUNNING or PAUSED, we set it to FAILED
00159             if(status==(long)Project::RUNNING || status==(long)Project::PAUSED)
00160             {
00161                 status=(long)Project::FAILED;
00162             }
00163             m_projList.Last().status = (Project::Status)status;
00164             if(textStream.ReadLine().StartsWith(_T("T")))
00165             {
00166                 m_projList.Last().skip = true;
00167             }
00168         }
00169         //we set the id generator we got from file
00170         Project::idGenerator = idGenTemp;
00171     }
00172 }
00173 
00174 void Batch::CancelBatch()
00175 {
00176     m_cancelled = true;
00177     for(int i=0; i<GetRunningCount(); i++)
00178     {
00179         CancelProject(i);
00180     }
00181     m_running = false;
00182 }
00183 void Batch::CancelProject(int index)
00184 {
00185     wxCommandEvent event;
00186     if(GetRunningCount()==1)
00187     {
00188         m_paused = false;
00189     }
00190     m_stitchFrames.Item(index)->OnCancel(event);
00191     if(GetRunningCount()==0)
00192     {
00193         m_running = false;
00194     }
00195 }
00196 void Batch::ChangePrefix(int index, wxString newPrefix)
00197 {
00198     m_projList.Item(index).prefix = newPrefix;
00199 }
00200 
00201 bool Batch::CheckProjectExistence() //used only in console version
00202 {
00203 #ifdef __WXMSW__  //on windows we run a loop every second to check if running processes are still active
00204     bool exist = true;
00205     HANDLE process;
00206     DWORD exitState;
00207     while(exist)
00208     {
00209         exist = false;
00210 
00211         for(unsigned int i=0; i<m_stitchFrames.GetCount(); i++)
00212         {
00213             try
00214             {
00215                 process = OpenProcess(PROCESS_QUERY_INFORMATION,true,m_stitchFrames.Item(i)->GetProcessId());
00216                 GetExitCodeProcess(process,&exitState);
00217             }
00218             catch(::exception e)
00219             {
00220                 exitState=1;
00221             }
00222             if(exitState==STILL_ACTIVE)
00223             {
00224                 exist=true;
00225             }
00226             else if(exitState!=0)
00227             {
00228                 SetStatus(GetIndex(m_stitchFrames.Item(i)->GetProjectId()),Project::FAILED);
00229             }
00230             CloseHandle(process);
00231         }
00232         wxSleep(1);
00233     }
00234 #else //not __WXMSW__, on Linux we wait for each of the processes to complete
00235     int status;
00236     int pid;
00237     for(unsigned int i=0; i<m_stitchFrames.GetCount(); i++)
00238     {
00239         pid = m_stitchFrames.Item(i)->GetProcessId();
00240         if(waitpid(pid,&status,0)==-1)
00241         {
00242             SetStatus(GetIndex(m_stitchFrames.Item(i)->GetProjectId()),Project::FAILED);    //we set to failed if waitpid terminated with an error
00243         }
00244         if(!WIFEXITED(status) || WEXITSTATUS(status)!=0)
00245         {
00246             SetStatus(GetIndex(m_stitchFrames.Item(i)->GetProjectId()),Project::FAILED);    //we set to failed if child terminated abnormally or with a bad exit code
00247         }
00248     }
00249 #endif
00250 
00251     wxProcessEvent event;
00252     for(int i=m_stitchFrames.GetCount()-1; i>=0; i--)
00253     {
00254         event.SetId(m_stitchFrames.Item(i)->GetProjectId());
00255         if(GetStatus(GetIndex(m_stitchFrames.Item(i)->GetProjectId()))==Project::FAILED)
00256         {
00257             event.SetTimestamp(-1);    //a failed exit code cannot be set to a wxWidgets event, so we fake it inside event's timestamp
00258         }
00259         OnProcessTerminate(event);
00260     }
00261     return true;
00262 }
00263 
00264 int Batch::ClearBatch()
00265 {
00266     if(m_stitchFrames.GetCount()!=0)
00267     {
00268         if(gui)
00269         {
00270             wxMessageDialog message(this, _("Cannot clear batch in progress.\nDo you want to cancel it?"),
00271 #ifdef _WINDOWS
00272                                     _("PTBatcherGUI"),
00273 #else
00274                                     wxT(""),
00275 #endif
00276                                     wxYES | wxCANCEL | wxICON_INFORMATION);
00277             if(message.ShowModal()==wxID_YES)
00278             {
00279                 CancelBatch();
00280 
00281                 //we set a flag so we don't process terminating events
00282                 m_clearedInProgress = true;
00283                 Project::idGenerator=1;
00284                 m_projList.Clear();
00285                 if(gui)
00286                 {
00287                     ((wxFrame*)GetParent())->SetStatusText(_("Cleared batch."));
00288                 }
00289                 else if(verbose)
00290                 {
00291                     cout << "Cleared batch." << endl;
00292                 }
00293                 return 2;
00294             }
00295         }
00296         else if(verbose)
00297         {
00298             cout << "Error: Cannot clear batch in progress." << endl;
00299         }
00300         return 1;
00301         //TO-DO: return
00302     }
00303     else
00304     {
00305         Project::idGenerator=1;
00306         m_projList.Clear();
00307         if(gui)
00308         {
00309             ((wxFrame*)GetParent())->SetStatusText(_("Cleared batch."));
00310         }
00311         else if(verbose)
00312         {
00313             cout << "Cleared batch." << endl;
00314         }
00315         return 0;
00316     }
00317 }
00318 
00319 bool Batch::CompareProjectsInLists(int stitchListIndex, int batchListIndex)
00320 {
00321     return m_stitchFrames.Item(stitchListIndex)->GetProjectId() == m_projList.Item(batchListIndex).id;
00322 }
00323 
00324 int Batch::GetFirstAvailable()
00325 {
00326     unsigned int i = 0;
00327     while(i<m_projList.Count())
00328     {
00329         if(m_projList.Item(i).skip || m_projList.Item(i).status!=Project::WAITING)
00330         {
00331             i++;
00332         }
00333         else
00334         {
00335             break;
00336         }
00337     }
00338     if((m_projList.Count() == 0) || (i == m_projList.Count()))
00339     {
00340         //no projects are available anymore
00341         return -1;
00342     }
00343     else
00344     {
00345         return i;
00346     }
00347 }
00348 
00349 int Batch::GetIndex(int id)
00350 {
00351     for(unsigned int i=0; i<m_projList.GetCount(); i++)
00352     {
00353         if(m_projList.Item(i).id==id)
00354         {
00355             return i;
00356         }
00357     }
00358     return -1;
00359 }
00360 
00361 Project* Batch::GetProject(int index)
00362 {
00363     return (Project*)&m_projList.Item(index);
00364 }
00365 
00366 int Batch::GetProjectCount()
00367 {
00368     return m_projList.GetCount();
00369 }
00370 
00371 int Batch::GetProjectCountByPath(wxString path)
00372 {
00373     int count = 0;
00374     for(unsigned int i=0; i<m_projList.GetCount(); i++)
00375     {
00376         if(!m_projList.Item(i).skip && (path.Cmp(m_projList.Item(i).path)==0))
00377         {
00378             count++;
00379         }
00380     }
00381     return count;
00382 }
00383 
00384 int Batch::GetRunningCount()
00385 {
00386     return m_stitchFrames.GetCount();
00387 }
00388 
00389 Project::Status Batch::GetStatus(int index)
00390 {
00391     if((unsigned int)index<m_projList.GetCount())
00392     {
00393         return m_projList.Item(index).status;
00394     }
00395     else if(gui)
00396     {
00397         wxMessageBox(wxString::Format(_("Error: Could not get status, project with index %d is not in list."),index),_("Error!"),wxOK | wxICON_INFORMATION );
00398     }
00399     else if(verbose)
00400     {
00401         cout << "Error: Could not get status, project with index " << index << " is not in list." << endl;
00402     }
00403     return Project::MISSING;
00404 }
00405 
00406 bool Batch::IsRunning()
00407 {
00408     return m_running;
00409 };
00410 
00411 bool Batch::IsPaused()
00412 {
00413     return m_paused;
00414 }
00415 
00416 void Batch::ListBatch()
00417 {
00418     if(m_projList.GetCount() == 0)
00419     {
00420         cout << "Batch is empty." << endl;
00421     }
00422     else
00423     {
00424         cout << "List of projects in batch:" << endl <<
00425              "[ID] [project path] [output filename] [status]" << endl <<
00426              "-------------------------------------" << endl;
00427         for(unsigned int i=0; i<m_projList.GetCount(); i++)
00428         {
00429             cout << m_projList.Item(i).id << "  "       << (const char*)m_projList.Item(i).path.char_str()  << "  " << (const char*)m_projList.Item(i).prefix.char_str()
00430                  << "  " << (const char*)m_projList.Item(i).GetStatusText().char_str() << endl;
00431         }
00432     }
00433 }
00434 
00435 int Batch::LoadBatchFile(wxString file)
00436 {
00437     int clearCode = ClearBatch();
00438     if(clearCode==0)
00439     {
00440         AppendBatchFile(file);
00441         return 0;
00442     }
00443     else if(clearCode==2)
00444     {
00445         AppendBatchFile(file);
00446         return 2;
00447     }
00448     else if(gui)
00449     {
00450         wxMessageBox(_("Error: Could not load batch file."));
00451     }
00452     else if(verbose)
00453     {
00454         cout << "Error: Could not load batch file." << endl;
00455     }
00456     return 1;
00457 }
00458 
00459 int Batch::LoadTemp()
00460 {
00461     wxDir* workingDir = new wxDir(wxStandardPaths::Get().GetUserConfigDir());
00462     wxString pending;
00463     wxString fileTemp = _T(".ptbt*");
00464     wxString temp = _T("");
00465     //we check for existing temporary files
00466     if(workingDir->GetFirst(&temp,fileTemp,wxDIR_FILES | wxDIR_HIDDEN))
00467     {
00468         //we find the last existing tempfile (there should be at most two, but we check for multiple just in case)
00469         while(workingDir->GetNext(&pending))
00470         {
00471             wxFileName tempFile(temp);
00472             wxFileName pendingFile(pending);
00473             wxDateTime* create1 = new wxDateTime();
00474             wxDateTime* create2 = new wxDateTime();
00475             if(tempFile.FileExists() && pendingFile.FileExists())
00476             {
00477                 tempFile.GetTimes(NULL,NULL,create1);
00478                 pendingFile.GetTimes(NULL,NULL,create2);
00479                 if(create2->IsLaterThan(*create1))
00480                 {
00481                     wxRemoveFile(temp);
00482                     temp=wxString(pending);
00483                 }
00484             }
00485             else
00486             {
00487                 //wxMessageBox( _T("Error reading temporary file"),_T("Error!"),wxOK | wxICON_INFORMATION );
00488                 return 1;
00489             }
00490         }
00491     }
00492     //we load the data from the temp file
00493     AppendBatchFile(workingDir->GetName()+wxFileName::GetPathSeparator()+temp);
00494     if(verbose && !gui)
00495     {
00496         cout << "Loaded temp file." << endl;
00497     }
00498     return 0;
00499 }
00500 
00501 bool Batch::NoErrors()
00502 {
00503     for(unsigned int i=0; i<m_projList.GetCount(); i++)
00504     {
00505         if(m_projList.Item(i).status==Project::FAILED)
00506         {
00507             return false;
00508         }
00509     }
00510     return true;
00511 }
00512 
00513 void Batch::OnProcessTerminate(wxProcessEvent& event)
00514 {
00515     //we find the right pointer to remove
00516     unsigned int i = 0;
00517     while(i < m_stitchFrames.GetCount() &&
00518             m_stitchFrames.Item(i)->GetProjectId()!=event.GetId())
00519     {
00520         i++;
00521     }
00522     m_stitchFrames.RemoveAt(i);
00523     if(m_clearedInProgress)
00524     {
00525         if(m_stitchFrames.GetCount()==0)
00526         {
00527             m_paused = false;
00528             m_running = false;
00529             m_cancelled = false;
00530             m_clearedInProgress = false;
00531         }
00532     }
00533     else
00534     {
00535         if(m_stitchFrames.GetCount()==0)
00536         {
00537             m_paused = false;
00538         }
00539         i = GetIndex(event.GetId());
00540         wxString savedLogfile=wxEmptyString;
00541         if(saveLog || event.GetExitCode() != 0 || event.GetTimestamp()==-1)
00542         {
00543             //get filename for automatic saving of log file
00544             wxFileName logFile(m_projList.Item(i).path);
00545             logFile.MakeAbsolute();
00546             logFile.SetExt(wxT("log"));
00547             wxString name=logFile.GetName();
00548             unsigned int i=1;
00549             while(logFile.FileExists() && i<1000)
00550             {
00551                 logFile.SetName(wxString::Format(wxT("%s_%d"),name.c_str(),i));
00552                 i++;
00553             };
00554             if(i<1000)
00555             {
00556                 //now save log file
00557                 if(((RunStitchFrame*)(event.GetEventObject()))->SaveLog(logFile.GetFullPath()))
00558                 {
00559                     savedLogfile=logFile.GetFullPath();
00560                 }
00561             };
00562         };
00563         if (event.GetExitCode() != 0 || event.GetTimestamp()==-1) //timestamp is used as a fake exit code because it cannot be set manually
00564         {
00565             m_projList.Item(i).status=Project::FAILED;
00566             struct FailedProject failedProject;
00567             failedProject.project=m_projList.Item(i).path;
00568             failedProject.logfile=savedLogfile;
00569             //remember failed project
00570             m_failedProjects.push_back(failedProject);
00571         }
00572         else
00573         {
00574             m_projList.Item(i).status=Project::FINISHED;
00575             // don't sent event for command app
00576             if(gui && m_projList.Item(i).id>=0)
00577             {
00578                 bool notifyParent=false;
00579                 if(autostitch && m_projList.Item(i).target==Project::DETECTING)
00580                 {
00581                     wxFileName name(m_projList.Item(i).path);
00582                     AddProjectToBatch(m_projList.Item(i).path,name.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + name.GetName(),Project::STITCHING);
00583                     notifyParent=true;
00584                 };
00585                 if(autoremove)
00586                 {
00587                     RemoveProjectAtIndex(i);
00588                     SaveTemp();
00589                     notifyParent=true;
00590                 };
00591                 if(notifyParent)
00592                 {
00593                     wxCommandEvent e(EVT_UPDATE_PARENT,wxID_ANY);
00594                     GetParent()->GetEventHandler()->AddPendingEvent(e);
00595                 };
00596             };
00597         }
00598         if(!m_cancelled && !m_paused)
00599         {
00600             if(AllDone())
00601             {
00602                 SaveTemp();
00603                 m_running = false;
00604                 if(NoErrors())
00605                 {
00606                     if(gui)
00607                     {
00608                         wxCommandEvent e(EVT_INFORMATION,wxID_ANY);
00609                         e.SetString(_("Batch successfully completed."));
00610                         GetParent()->GetEventHandler()->AddPendingEvent(e);
00611                     }
00612                     else
00613                         //cout << "Project \"" << m_projList.Item(i).path.char_str() << "\" finished. Batch successfully completed." << endl;
00614                     {
00615                         cout << "Batch successfully completed." << endl;
00616                     }
00617                 }
00618                 else
00619                 {
00620                     if(gui)
00621                     {
00622                         SetStatusText(_("Batch completed with errors."));
00623                         if(!shutdown)
00624                         {
00625                             if(gui)
00626                             {
00627                                 //notify parent, that at least one project failed
00628                                 wxCommandEvent e(EVT_BATCH_FAILED,wxID_ANY);
00629                                 GetParent()->GetEventHandler()->AddPendingEvent(e);
00630                             };
00631                         };
00632                     }
00633                     else
00634                         //cout << "Project \"" << m_projList.Item(i).path.char_str() << "\" finished. Batch completed with errors." << endl;
00635                     {
00636                         cout << "Batch completed with errors." << endl;
00637                     }
00638                 }
00639                 if(shutdown)    //after we are finished we turn off the computer if checked
00640                 {
00641                     if(gui)
00642                     {
00643                         wxProgressDialog progress(_("Initializing shutdown..."), _("Shutting down..."),49,this,
00644                                                   wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_CAN_SKIP);
00645                         progress.Fit();
00646                         int i = 0;
00647                         bool skip = false;
00648                         while(progress.Update(i, _("Shutting down..."),&skip))
00649                         {
00650                             if(skip || i==50)
00651                             {
00652                                 /*wxMessageDialog message(this,_T("Krneksa"));
00653                                 message.ShowModal();
00654                                 break;*/
00655                                 wxShutdown(wxSHUTDOWN_POWEROFF);
00656                             }
00657                             i++;
00658 #if defined __WXMSW__
00659                             Sleep(200);
00660 #else
00661                             sleep(200);
00662 #endif
00663                         }
00664                         progress.Close();
00665                     }
00666                     else
00667                     {
00668                         if(!wxShutdown(wxSHUTDOWN_POWEROFF))
00669                         {
00670                             if(gui)
00671 #ifdef __WXMSW__
00672                                 wxMessageBox(_("Error shutting down."));
00673 #else
00674                                 wxMessageBox(_("Error shutting down. Do you have root privileges?"));
00675 #endif
00676                             else
00677 #ifdef __WXMSW__
00678                                 cout << "Error shutting down." << endl;
00679 #else
00680                                 cout << "Error shutting down. Do you have root privileges?" << endl;
00681 #endif
00682                         }
00683                     }
00684                 }
00685             }
00686             else
00687             {
00688                 if(parallel)    //if we are running in parallel
00689                 {
00690                     //the last executed process in parallel runs next
00691                     if(GetRunningCount() == 0)
00692                     {
00693                         //SetStatusText(_T("Project \""+m_projList.Item(i).path)+_T("\" finished. Running next project..."));
00694                         RunNextInBatch();
00695                     }
00696                     else
00697                     {
00698                         //SetStatusText(_T("Project \""+m_projList.Item(i).path)+_T("\" finished. Waiting for all in parallel to complete..."));
00699                     }
00700                 }
00701                 else
00702                 {
00703                     //SetStatusText(_T("Project \""+m_projList.Item(i).path)+_T("\" finished. Running next project..."));
00704                     RunNextInBatch();
00705                 }
00706             }
00707         }
00708         else
00709         {
00710             //after all processes have ended on a cancel, we reset the boolean back to false
00711             //if(stitchFrames.GetCount()==0)
00712             if(GetRunningCount()==0)
00713             {
00714                 m_cancelled=false;
00715             }
00716         }
00717     }
00718 }
00719 
00720 bool Batch::OnStitch(wxString scriptFile, wxString outname, int id)
00721 {
00722     if(wxIsEmpty(scriptFile))
00723     {
00724         wxString defaultdir = wxConfigBase::Get()->Read(wxT("/actualPath"),wxT(""));
00725         wxFileDialog dlg(0,
00726                          _("Specify project source project file"),
00727                          defaultdir, wxT(""),
00728                          _("Project files (*.pto,*.ptp,*.pts,*.oto)|*.pto;*.ptp;*.pts;*.oto;|All files (*)|*"),
00729                          wxFD_OPEN, wxDefaultPosition);
00730 
00731         dlg.SetDirectory(wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")));
00732         if (dlg.ShowModal() == wxID_OK)
00733         {
00734             wxConfig::Get()->Write(wxT("/actualPath"), dlg.GetDirectory());  // remember for later
00735             wxFileDialog dlg2(0,_("Specify output prefix"),
00736                               wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")),
00737                               wxT(""), wxT(""),
00738                               wxFD_SAVE, wxDefaultPosition);
00739             dlg2.SetDirectory(wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")));
00740             if (dlg2.ShowModal() == wxID_OK)
00741             {
00742                 outname = dlg2.GetPath();
00743             }
00744             else     // bail
00745             {
00746                 wxLogError( _("No output prefix specified"));
00747                 return false;
00748             }
00749             scriptFile = dlg.GetPath();
00750         }
00751         else     // bail
00752         {
00753             return false;
00754             wxLogError( _("No project files specified"));
00755         }
00756     }
00757 
00758     if(!gui)
00759     {
00760         cout << "Stitching with input file " << (const char*)scriptFile.mb_str(wxConvLocal) << "..." << endl;
00761     }
00762 
00763     // check output filename
00764     wxFileName outfn(outname);
00765     wxString ext = outfn.GetExt();
00766     // remove extension if it indicates an image file
00767     if (ext.CmpNoCase(wxT("jpg")) == 0 || ext.CmpNoCase(wxT("jpeg")) == 0 ||
00768             ext.CmpNoCase(wxT("tif")) == 0 || ext.CmpNoCase(wxT("tiff")) == 0 ||
00769             ext.CmpNoCase(wxT("png")) == 0 || ext.CmpNoCase(wxT("exr")) == 0 ||
00770             ext.CmpNoCase(wxT("pnm")) == 0 || ext.CmpNoCase(wxT("hdr")) == 0)
00771     {
00772         outfn.ClearExt();
00773         outname = outfn.GetFullPath();
00774     }
00775 
00776     RunStitchFrame* stitchFrame = new RunStitchFrame(this, wxT("Hugin Stitcher"), wxDefaultPosition, wxSize(640,600));
00777     stitchFrame->SetProjectId(id);
00778     if(verbose && gui)
00779     {
00780         stitchFrame->Show( true );
00781         wxTheApp->SetTopWindow( stitchFrame );
00782     }
00783 
00784     wxFileName basename(scriptFile);
00785     stitchFrame->SetTitle(wxString::Format(_("%s - Stitching"), basename.GetName().c_str()));
00786     if(overwrite)
00787     {
00788         stitchFrame->m_stitchPanel->SetOverwrite(true);
00789     }
00790 
00791     bool n = stitchFrame->StitchProject(scriptFile, outname, progs);
00792     if(n)
00793     {
00794         m_stitchFrames.Add(stitchFrame);
00795     }
00796     else
00797     {
00798         stitchFrame->Close();
00799     }
00800     return n;
00801 
00802 }
00803 
00804 bool Batch::OnDetect(wxString scriptFile, int id)
00805 {
00806     if(!gui)
00807     {
00808         cout << "Running assistant with input file " << (const char*)scriptFile.mb_str(wxConvLocal) << "..." << endl;
00809     }
00810 
00811     RunStitchFrame* stitchFrame = new RunStitchFrame(this, wxT("Hugin Assistant"), wxDefaultPosition, wxSize(640,600));
00812     stitchFrame->SetProjectId(id);
00813     if(verbose && gui)
00814     {
00815         stitchFrame->Show( true );
00816         wxTheApp->SetTopWindow( stitchFrame );
00817     }
00818 
00819     wxFileName basename(scriptFile);
00820     stitchFrame->SetTitle(wxString::Format(_("%s - Assistant"), basename.GetName().c_str()));
00821 
00822     bool n = stitchFrame->DetectProject(scriptFile, progsAss);
00823     if(n)
00824     {
00825         m_stitchFrames.Add(stitchFrame);
00826     }
00827     else
00828     {
00829         stitchFrame->Close();
00830     }
00831     return n;
00832 
00833 }
00834 
00835 void Batch::PauseBatch()
00836 {
00837     if(!m_paused)
00838     {
00839         m_paused = true;
00840         for(int i=0; i<GetRunningCount(); i++)
00841         {
00842             m_stitchFrames.Item(i)->m_stitchPanel->PauseStitch();
00843         }
00844         for(unsigned int i=0; i<m_projList.GetCount(); i++)
00845         {
00846             if(m_projList.Item(i).status==Project::RUNNING)
00847             {
00848                 m_projList.Item(i).status=Project::PAUSED;
00849             }
00850         }
00851     }
00852     else
00853     {
00854         m_paused = false;
00855         for(int i=0; i<GetRunningCount(); i++)
00856         {
00857             m_stitchFrames.Item(i)->m_stitchPanel->ContinueStitch();
00858         }
00859         for(unsigned int i=0; i<m_projList.GetCount(); i++)
00860         {
00861             if(m_projList.Item(i).status==Project::PAUSED)
00862             {
00863                 m_projList.Item(i).status=Project::RUNNING;
00864             }
00865         }
00866     }
00867 }
00868 
00869 void Batch::RemoveProject(int id)
00870 {
00871     int index;
00872     if((index=GetIndex(id)) != -1)
00873     {
00874         RemoveProjectAtIndex(GetIndex(id));
00875     }
00876     else if(gui)
00877     {
00878         wxMessageBox(wxString::Format(_("Error removing, project with id %d is not in list."),id),_("Error!"),wxOK | wxICON_INFORMATION );
00879     }
00880     else if(verbose)
00881     {
00882         cout << "Error: Project with id " << id << " is not in list." << endl;
00883     }
00884 }
00885 
00886 void Batch::RemoveProjectAtIndex(int selIndex)
00887 {
00888     //we delete only successful project files and no applications
00889     if(deleteFiles
00890             && m_projList.Item(selIndex).id>=0
00891             && m_projList.Item(selIndex).status==Project::FINISHED)
00892     {
00893         wxFileName file(m_projList.Item(selIndex).path);
00894         if(file.FileExists())
00895         {
00896             if(!wxRemoveFile(file.GetFullPath()))
00897             {
00898                 if(gui)
00899                 {
00900                     wxMessageBox( _("Error: Could not delete project file ")+file.GetFullPath(),_("Error!"),wxOK | wxICON_INFORMATION );
00901                 }
00902                 else if(verbose)
00903                 {
00904                     cout << "Error: Could not delete project file " << (const char*)file.GetFullPath().char_str() << endl;
00905                 }
00906             }
00907         }
00908     }
00909     m_projList.RemoveAt(selIndex);
00910     if(m_projList.GetCount()==0) //reset the id generator on empty list
00911     {
00912         Project::idGenerator=1;
00913     }
00914 }
00915 
00916 void Batch::RunBatch()
00917 {
00918     if(!gui && m_projList.GetCount() == 0)
00919     {
00920         cout << "Batch is empty." << endl;
00921     }
00922     else if(!m_running)
00923     {
00924         m_failedProjects.clear();
00925         if(gui)
00926         {
00927             ((wxFrame*)GetParent())->SetStatusText(_("Running batch..."));
00928         }
00929         else
00930         {
00931             cout << "Running batch..." << endl;
00932         }
00933         m_running = true;
00934         RunNextInBatch();
00935     }
00936     else if(gui)
00937     {
00938         ((wxFrame*)GetParent())->SetStatusText(_("Batch already in progress."));
00939     }
00940 }
00941 
00942 void Batch::RunNextInBatch()
00943 {
00944     bool value;
00945     bool repeat = true;
00946     unsigned int i;
00947     while(((i=GetFirstAvailable())!=-1) && repeat)
00948     {
00949         //execute command line instructions
00950         if(m_projList.Item(i).id<0)
00951         {
00952             if(gui)
00953             {
00954                 SetStatusText(_("Running command \"")+m_projList.Item(i).path+_T("\""));
00955             }
00956             else
00957             {
00958                 cout << "Running command \"" << (const char*)m_projList.Item(i).path.char_str() << "\"" << endl;
00959             }
00960             m_projList.Item(i).status=Project::RUNNING;
00961             //we create a fake stitchFrame, so program waits for app to complete
00962             if(!gui)
00963             {
00964                 RunStitchFrame* stitchFrame = new RunStitchFrame(this, wxT("Hugin Stitcher"), wxDefaultPosition, wxSize(640,600));
00965                 stitchFrame->SetProjectId(m_projList.Item(i).id);
00966 
00967                 repeat = false;
00968                 int pid = wxExecute(m_projList.Item(i).path, wxEXEC_ASYNC);
00969                 stitchFrame->SetProcessId(pid);
00970                 m_stitchFrames.Add(stitchFrame);
00971             }
00972             else
00973             {
00974                 if(wxExecute(m_projList.Item(i).path, wxEXEC_SYNC)==0)
00975                 {
00976                     m_projList.Item(i).status=Project::FINISHED;
00977                 }
00978                 else
00979                 {
00980                     m_projList.Item(i).status=Project::FAILED;
00981                 }
00982             }
00983         }
00984         else
00985         {
00986             //we run in sequence
00987             if(!parallel)
00988             {
00989                 m_projList.Item(i).status=Project::RUNNING;
00990                 m_running = true;
00991                 if(m_projList.Item(i).target==Project::STITCHING)
00992                 {
00993                     if(gui)
00994                     {
00995                         wxCommandEvent e(EVT_INFORMATION,wxID_ANY);
00996                         e.SetString(wxString::Format(_("Now stitching: %s"),m_projList.Item(i).path.c_str()));
00997                         GetParent()->GetEventHandler()->AddPendingEvent(e);
00998                     };
00999                     value = OnStitch(m_projList.Item(i).path, m_projList.Item(i).prefix, m_projList.Item(i).id);
01000                 }
01001                 else
01002                 {
01003                     if(gui)
01004                     {
01005                         wxCommandEvent e(EVT_INFORMATION,wxID_ANY);
01006                         e.SetString(wxString::Format(_("Now detecting: %s"),m_projList.Item(i).path.c_str()));
01007                         GetParent()->GetEventHandler()->AddPendingEvent(e);
01008                     };
01009                     value = OnDetect(m_projList.Item(i).path,m_projList.Item(i).id);
01010                 };
01011                 if(!value)
01012                 {
01013                     m_projList.Item(i).status=Project::FAILED;
01014                 }
01015                 else
01016                 {
01017                     repeat = false;
01018                 }
01019             }
01020             else
01021             {
01022                 while((i = GetFirstAvailable())!=-1)
01023                 {
01024                     if(m_projList.Item(i).id<0)
01025                     {
01026                         break;
01027                     }
01028                     m_projList.Item(i).status=Project::RUNNING;
01029                     m_running = true;
01030                     if(m_projList.Item(i).target==Project::STITCHING)
01031                     {
01032                         if(gui)
01033                         {
01034                             wxCommandEvent e(EVT_INFORMATION,wxID_ANY);
01035                             e.SetString(wxString::Format(_("Now stitching: %s"),m_projList.Item(i).path.c_str()));
01036                             GetParent()->GetEventHandler()->AddPendingEvent(e);
01037                         };
01038                         value = OnStitch(m_projList.Item(i).path, m_projList.Item(i).prefix, m_projList.Item(i).id);
01039                     }
01040                     else
01041                     {
01042                         if(gui)
01043                         {
01044                             wxCommandEvent e(EVT_INFORMATION,wxID_ANY);
01045                             e.SetString(wxString::Format(_("Now detecting: %s"),m_projList.Item(i).path.c_str()));
01046                             GetParent()->GetEventHandler()->AddPendingEvent(e);
01047                         };
01048                         value = OnDetect(m_projList.Item(i).path,m_projList.Item(i).id);
01049                     };
01050                     if(!value)
01051                     {
01052                         m_projList.Item(i).status=Project::FAILED;
01053                     }
01054                     else
01055                     {
01056                         repeat = false;
01057                     }
01058                 }
01059             }
01060         }
01061     }
01062     if(AllDone())
01063     {
01064         m_running = false;
01065     }
01066     else if(!gui)
01067     {
01068         CheckProjectExistence();
01069     }
01070 }
01071 
01072 void Batch::SaveBatchFile(wxString file)
01073 {
01074     wxFileOutputStream fileStream(file);
01075 #ifdef __WXMSW__
01076     wxTextOutputStream textStream(fileStream, wxEOL_NATIVE, wxConvLocal);
01077 #else
01078     wxTextOutputStream textStream(fileStream);
01079 #endif
01080     //we write current idGenerator to file
01081     wxString line = _T("");
01082     line << Project::idGenerator;
01083     textStream.WriteString(line+_T("\n"));
01084     //then for each project: project path, prefix, id, status, skip
01085     for(unsigned int i = 0; i< m_projList.GetCount(); i++)
01086     {
01087         textStream.WriteString(m_projList.Item(i).path+_T("\n"));
01088         if(m_projList.Item(i).target==Project::STITCHING)
01089         {
01090             textStream.WriteString(m_projList.Item(i).prefix+_T("\n"));
01091         }
01092         else
01093         {
01094             textStream.WriteString(_T("\n"));
01095         };
01096         line = _T("");
01097         line << m_projList.Item(i).id;
01098         textStream.WriteString(line+_T("\n"));
01099         line = _T("");
01100         line << m_projList.Item(i).status;
01101         textStream.WriteString(line+_T("\n"));
01102         if(m_projList.Item(i).skip)
01103         {
01104             textStream.WriteString(_T("T\n"));
01105         }
01106         else
01107         {
01108             textStream.WriteString(_T("F\n"));
01109         }
01110     }
01111     fileStream.Close();
01112     m_lastFile = file;
01113     wxFileName aFile(file);
01114     aFile.GetTimes(NULL,NULL,&m_lastmod);
01115 }
01116 
01117 void Batch::SaveTemp()
01118 {
01119     wxDir* workingDir = new wxDir(wxStandardPaths::Get().GetUserConfigDir());
01120     wxString fileTemp = _T(".ptbt*");
01121     //we get the old temp file
01122     fileTemp = workingDir->FindFirst(workingDir->GetName(),fileTemp,wxDIR_FILES | wxDIR_HIDDEN);
01123     wxFileName oldFile(fileTemp);
01124     //we alternate between 0 and 1
01125     wxString suffix;
01126     if(fileTemp.EndsWith(_T("0")))
01127     {
01128         suffix = _T("1");
01129     }
01130     else
01131     {
01132         suffix = _T("0");
01133     }
01134     SaveBatchFile(wxStandardPaths::Get().GetUserConfigDir()+wxFileName::GetPathSeparator()+_T(".ptbt")+suffix);
01135     if(verbose && !gui)
01136     {
01137         cout << "Saved temp file." << endl;
01138     }
01139     //we remove the previous temp file
01140     if(oldFile.FileExists())
01141     {
01142         wxRemoveFile(fileTemp);
01143     }
01144 }
01145 
01146 void Batch::SetStatus(int index,Project::Status status)
01147 {
01148     if((unsigned int)index<m_projList.GetCount())
01149     {
01150         m_projList.Item(index).status = status;
01151     }
01152     else if(gui)
01153     {
01154         wxMessageBox(wxString::Format(_("Error: Could not set status, project with index %d is not in list."),index),_("Error!"),wxOK | wxICON_INFORMATION );
01155     }
01156     else if(verbose)
01157     {
01158         cout << "Error: Could not set status, project with index " << index << " is not in list." << endl;
01159     }
01160 }
01161 
01162 void Batch::SwapProject(int index)
01163 {
01164     Project* proj = m_projList.Detach(index+1);
01165     m_projList.Insert(proj,index);
01166 }
01167 
01168 void Batch::ShowOutput(bool isVisible)
01169 {
01170     for(unsigned int i=0; i<m_stitchFrames.Count(); i++)
01171     {
01172         m_stitchFrames.Item(i)->Show(isVisible);
01173     };
01174 };
01175 
01176 wxString Batch::GetFailedProjectName(unsigned int i)
01177 {
01178     if(i>=0 && i<m_failedProjects.size())
01179     {
01180         return m_failedProjects[i].project;
01181     }
01182     else
01183     {
01184         return wxEmptyString;
01185     }
01186 };
01187 
01188 wxString Batch::GetFailedProjectLog(unsigned int i)
01189 {
01190     if(i>=0 && i<m_failedProjects.size())
01191     {
01192         return m_failedProjects[i].logfile;
01193     }
01194     else
01195     {
01196         return wxEmptyString;
01197     }
01198 };

Generated on Wed May 22 01:25:37 2013 for Hugintrunk by  doxygen 1.3.9.1