00001
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
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
00063
00064
00065
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
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
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
00139
00140 long idGenTemp = 1;
00141 textStream.ReadLine().ToLong(&idGenTemp);
00142
00143 while((projectName = textStream.ReadLine()).Cmp(wxT(""))!=0)
00144 {
00145
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
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
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()
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);
00243 }
00244 if(!WIFEXITED(status) || WEXITSTATUS(status)!=0)
00245 {
00246 SetStatus(GetIndex(m_stitchFrames.Item(i)->GetProjectId()),Project::FAILED);
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);
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
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
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
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
00466 if(workingDir->GetFirst(&temp,fileTemp,wxDIR_FILES | wxDIR_HIDDEN))
00467 {
00468
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
00488 return 1;
00489 }
00490 }
00491 }
00492
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
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
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
00557 if(((RunStitchFrame*)(event.GetEventObject()))->SaveLog(logFile.GetFullPath()))
00558 {
00559 savedLogfile=logFile.GetFullPath();
00560 }
00561 };
00562 };
00563 if (event.GetExitCode() != 0 || event.GetTimestamp()==-1)
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
00570 m_failedProjects.push_back(failedProject);
00571 }
00572 else
00573 {
00574 m_projList.Item(i).status=Project::FINISHED;
00575
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
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
00628 wxCommandEvent e(EVT_BATCH_FAILED,wxID_ANY);
00629 GetParent()->GetEventHandler()->AddPendingEvent(e);
00630 };
00631 };
00632 }
00633 else
00634
00635 {
00636 cout << "Batch completed with errors." << endl;
00637 }
00638 }
00639 if(shutdown)
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
00653
00654
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)
00689 {
00690
00691 if(GetRunningCount() == 0)
00692 {
00693
00694 RunNextInBatch();
00695 }
00696 else
00697 {
00698
00699 }
00700 }
00701 else
00702 {
00703
00704 RunNextInBatch();
00705 }
00706 }
00707 }
00708 else
00709 {
00710
00711
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());
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
00745 {
00746 wxLogError( _("No output prefix specified"));
00747 return false;
00748 }
00749 scriptFile = dlg.GetPath();
00750 }
00751 else
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
00764 wxFileName outfn(outname);
00765 wxString ext = outfn.GetExt();
00766
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
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)
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
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
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
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
01081 wxString line = _T("");
01082 line << Project::idGenerator;
01083 textStream.WriteString(line+_T("\n"));
01084
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
01122 fileTemp = workingDir->FindFirst(workingDir->GetName(),fileTemp,wxDIR_FILES | wxDIR_HIDDEN);
01123 wxFileName oldFile(fileTemp);
01124
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
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 };