Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Batch.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
27 #ifdef _WIN32
28 #include "wx/msw/wrapwin.h"
29 #endif
30 #include "Batch.h"
31 #include <wx/stdpaths.h>
32 #ifdef __WXMSW__
33 #include <powrprof.h>
34 #ifdef _MSC_VER
35 #pragma comment(lib, "PowrProf.lib")
36 #endif
37 #endif
38 #include <wx/dir.h>
39 #ifndef __WXMSW__
40 #include <sys/wait.h>
41 #endif
42 
43 BEGIN_EVENT_TABLE(Batch, wxFrame)
44  EVT_END_PROCESS(-1, Batch::OnProcessTerminate)
46 
47 #if defined _WIN32 && defined Hugin_shared
48 DEFINE_LOCAL_EVENT_TYPE(EVT_BATCH_FAILED)
49 DEFINE_LOCAL_EVENT_TYPE(EVT_INFORMATION)
50 DEFINE_LOCAL_EVENT_TYPE(EVT_UPDATE_PARENT)
51 #else
52 DEFINE_EVENT_TYPE(EVT_BATCH_FAILED)
53 DEFINE_EVENT_TYPE(EVT_INFORMATION)
54 DEFINE_EVENT_TYPE(EVT_UPDATE_PARENT)
55 #endif
56 
57 Batch::Batch(wxFrame* parent) : wxFrame(parent, wxID_ANY, _T("Batch"))
58 {
59  //default flag settings
60  deleteFiles = false;
61  atEnd = DO_NOTHING;
62 #if wxCHECK_VERSION(3,1,0)
63  m_resBlocker = NULL;
64 #endif
65  overwrite = true;
66  verbose = false;
67  autoremove = false;
68  autostitch = false;
69  saveLog = false;
70  m_cancelled = false;
71  m_paused = false;
72  m_running = false;
73  m_clearedInProgress = false;
74 }
75 
77 {
78 #if wxCHECK_VERSION(3,1,0)
79  if (m_resBlocker != NULL)
80  {
81  delete m_resBlocker;
82  };
83 #endif
84 }
85 
86 void Batch::AddAppToBatch(wxString app)
87 {
88  Project* newApp = new Project(app);
89  m_projList.Add(newApp);
90 }
91 
92 void Batch::AddProjectToBatch(wxString projectFile, wxString outputFile, wxString userDefinedSequence, Project::Target target)
93 {
94  wxFileName projectName(projectFile);
95  wxFileName outName(outputFile);
96  projectName.Normalize(wxPATH_NORM_ABSOLUTE | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_SHORTCUT);
97  outName.Normalize(wxPATH_NORM_ABSOLUTE | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_SHORTCUT);
98 
99  if(!outputFile.IsEmpty() || target==Project::DETECTING)
100  {
101  Project* proj = new Project(projectName.GetFullPath(), outName.GetFullPath(), userDefinedSequence, target);
102  m_projList.Add(proj);
103  }
104  else
105  {
106  //on output set as "", it defaults to same path and name as project file
107  Project* proj = new Project(projectName.GetFullPath(), wxEmptyString, userDefinedSequence);
108  m_projList.Add(proj);
109  }
110 }
111 
113 {
114  for(unsigned int i=0; i<m_projList.GetCount(); i++)
115  {
116  if(m_projList.Item(i).status==Project::WAITING ||
117  m_projList.Item(i).status==Project::RUNNING ||
118  m_projList.Item(i).status==Project::PAUSED)
119  {
120  return false;
121  }
122  }
123  return true;
124 }
125 
126 void Batch::AppendBatchFile(wxString file)
127 {
128  if (wxFileName::FileExists(file))
129  {
130  wxFileInputStream fileStream(file);
131  wxFileConfig batchFile(fileStream);
132  //first line in file is idGenerator, we save it a temp variable, cause it gets set when adding projects
133  const long idGenTemp = batchFile.ReadLong("/Main/CurrentID", 1l);
134  const long projCount = batchFile.ReadLong("/Main/Count", 0l);
135  //then for each project: project path, prefix, id, status, skip
136  if (projCount > 0)
137  {
138  // we can not use GetFirstGroup/GetNextGroup because these function return the groups in alphabetical order
139  // and not in the order in the file
140  for (long i = 1; i <= projCount; ++i)
141  {
142  const wxString group = wxString::Format("Project_%ld", i);
143  if (batchFile.HasGroup(group))
144  {
145  batchFile.SetPath(group);
146  const wxString projectName = batchFile.Read("Project", wxEmptyString);
147  const wxString type = batchFile.Read("Type", "Stitching");
148  const long id = batchFile.ReadLong("Id", 1);
149  long status = batchFile.ReadLong("Status", (long)Project::WAITING);
150  const bool skip = batchFile.ReadBool("Skip", false);
151 
152  //we add project to internal list
153  if (id < 0)
154  {
155  // negative ID means command
156  AddAppToBatch(projectName);
157  }
158  else
159  {
160  const wxString userDefinedSequence = batchFile.Read("UserDefinedSequence", wxEmptyString);
161  if (type.CmpNoCase("Stitching") == 0)
162  {
163  const wxString prefix = batchFile.Read("Prefix", wxEmptyString);
164  AddProjectToBatch(projectName, prefix, userDefinedSequence);
165  }
166  else
167  {
168  if (type.CmpNoCase("Detecting") == 0)
169  {
170  AddProjectToBatch(projectName, wxEmptyString, userDefinedSequence, Project::DETECTING);
171  }
172  else
173  {
174  //unknow type, skipping
175  continue;
176  };
177  };
178  };
179  //if status was RUNNING or PAUSED, we set it to FAILED
180  if (status == (long)Project::RUNNING || status == (long)Project::PAUSED)
181  {
182  status = (long)Project::FAILED;
183  }
184  m_projList.Last().id = id;
185  m_projList.Last().status = (Project::Status)status;
186  m_projList.Last().skip = batchFile.ReadBool("Skip", false);
187  batchFile.SetPath("/");
188  };
189  };
190  };
191  //we set the id generator we got from file
192  Project::idGenerator = idGenTemp;
193  };
194 }
195 
197 {
198  m_cancelled = true;
199  for(int i=0; i<GetRunningCount(); i++)
200  {
201  CancelProject(i);
202  }
203 #if wxCHECK_VERSION(3,1,0)
204  if (m_resBlocker != NULL)
205  {
206  delete m_resBlocker;
207  m_resBlocker = NULL;
208  };
209 #endif
210  m_running = false;
211 }
212 void Batch::CancelProject(int index)
213 {
214  wxCommandEvent event;
215  if(GetRunningCount()==1)
216  {
217  m_paused = false;
218  }
219  m_stitchFrames.Item(index)->OnCancel(event);
220  if(GetRunningCount()==0)
221  {
222  m_running = false;
223  }
224 }
225 void Batch::ChangePrefix(int index, wxString newPrefix)
226 {
227  m_projList.Item(index).prefix = newPrefix;
228 }
229 
230 void Batch::ChangeUserDefined(int index, wxString newUserDefined)
231 {
232  m_projList.Item(index).userDefindSequence = newUserDefined;
233 }
234 
236 {
237  if(m_stitchFrames.GetCount()!=0)
238  {
239  wxMessageDialog message(this, _("Cannot clear batch in progress.\nDo you want to cancel it?"),
240 #ifdef _WIN32
241  _("PTBatcherGUI"),
242 #else
243  wxT(""),
244 #endif
245  wxYES_NO | wxICON_INFORMATION);
246  if(message.ShowModal()==wxID_YES)
247  {
248  CancelBatch();
249 
250  //we set a flag so we don't process terminating events
251  m_clearedInProgress = true;
253  m_projList.Clear();
254  ((wxFrame*)GetParent())->SetStatusText(_("Cleared batch."));
255  return 2;
256  }
257  return 1;
258  //TO-DO: return
259  }
260  else
261  {
263  m_projList.Clear();
264  ((wxFrame*)GetParent())->SetStatusText(_("Cleared batch."));
265  return 0;
266  }
267 }
268 
269 bool Batch::CompareProjectsInLists(int stitchListIndex, int batchListIndex)
270 {
271  return m_stitchFrames.Item(stitchListIndex)->GetProjectId() == m_projList.Item(batchListIndex).id;
272 }
273 
275 {
276  unsigned int i = 0;
277  while(i<m_projList.Count())
278  {
279  if(m_projList.Item(i).skip || m_projList.Item(i).status!=Project::WAITING)
280  {
281  i++;
282  }
283  else
284  {
285  break;
286  }
287  }
288  if((m_projList.Count() == 0) || (i == m_projList.Count()))
289  {
290  //no projects are available anymore
291  return -1;
292  }
293  else
294  {
295  return i;
296  }
297 }
298 
299 int Batch::GetIndex(int id)
300 {
301  for(unsigned int i=0; i<m_projList.GetCount(); i++)
302  {
303  if(m_projList.Item(i).id==id)
304  {
305  return i;
306  }
307  }
308  return -1;
309 }
310 
312 {
313  return (Project*)&m_projList.Item(index);
314 }
315 
317 {
318  return m_projList.GetCount();
319 }
320 
322 {
323  int count = 0;
324  for(unsigned int i=0; i<m_projList.GetCount(); i++)
325  {
326  if(!m_projList.Item(i).skip && (path.Cmp(m_projList.Item(i).path)==0))
327  {
328  count++;
329  }
330  }
331  return count;
332 }
333 
335 {
336  return m_stitchFrames.GetCount();
337 }
338 
340 {
341  if((unsigned int)index<m_projList.GetCount())
342  {
343  return m_projList.Item(index).status;
344  }
345  else
346  {
347  wxMessageBox(wxString::Format(_("Error: Could not get status, project with index %d is not in list."),index),_("Error!"),wxOK | wxICON_INFORMATION );
348  }
349  return Project::MISSING;
350 }
351 
353 {
354  return m_running;
355 };
356 
358 {
359  return m_paused;
360 }
361 
362 int Batch::LoadBatchFile(wxString file)
363 {
364  int clearCode = ClearBatch();
365  if(clearCode==0)
366  {
367  AppendBatchFile(file);
368  return 0;
369  }
370  else if(clearCode==2)
371  {
372  AppendBatchFile(file);
373  return 2;
374  }
375  else
376  {
377  wxMessageBox(_("Error: Could not load batch file."));
378  };
379  return 1;
380 }
381 
383 {
384  wxString batchQueue = GetBatchFilename();
385  //we load the data from the temp file
386  if (wxFileName::FileExists(batchQueue))
387  {
388  AppendBatchFile(batchQueue);
389  };
390  return 0;
391 }
392 
394 {
395  for(unsigned int i=0; i<m_projList.GetCount(); i++)
396  {
397  if(m_projList.Item(i).status==Project::FAILED)
398  {
399  return false;
400  }
401  }
402  return true;
403 }
404 
405 void Batch::OnProcessTerminate(wxProcessEvent& event)
406 {
407  //we find the right pointer to remove
408  unsigned int i = 0;
409  while(i < m_stitchFrames.GetCount() &&
410  m_stitchFrames.Item(i)->GetProjectId()!=event.GetId())
411  {
412  i++;
413  }
414  m_stitchFrames.RemoveAt(i);
416  {
417  if(m_stitchFrames.GetCount()==0)
418  {
419  m_paused = false;
420  m_running = false;
421  m_cancelled = false;
422  m_clearedInProgress = false;
423  }
424  }
425  else
426  {
427  if(m_stitchFrames.GetCount()==0)
428  {
429  m_paused = false;
430  }
431  i = GetIndex(event.GetId());
432  wxString savedLogfile=wxEmptyString;
433  if(saveLog || event.GetExitCode() != 0 || event.GetTimestamp()==-1)
434  {
435  //get filename for automatic saving of log file
436  wxFileName logFile(m_projList.Item(i).path);
437  logFile.MakeAbsolute();
438  logFile.SetExt(wxT("log"));
439  wxString name=logFile.GetName();
440  unsigned int i=1;
441  while(logFile.FileExists() && i<1000)
442  {
443  logFile.SetName(wxString::Format(wxT("%s_%d"),name.c_str(),i));
444  i++;
445  };
446  if(i<1000)
447  {
448  //now save log file
449  if((static_cast<RunStitchFrame*>(event.GetEventObject()))->SaveLog(logFile.GetFullPath()))
450  {
451  savedLogfile=logFile.GetFullPath();
452  }
453  };
454  };
455  if (event.GetExitCode() != 0 || event.GetTimestamp()==-1) //timestamp is used as a fake exit code because it cannot be set manually
456  {
457  m_projList.Item(i).status=Project::FAILED;
458  struct FailedProject failedProject;
459  failedProject.project=m_projList.Item(i).path;
460  failedProject.logfile=savedLogfile;
461  //remember failed project
462  m_failedProjects.push_back(failedProject);
463  }
464  else
465  {
466  m_projList.Item(i).status=Project::FINISHED;
467  // don't sent event for command app
468  if(m_projList.Item(i).id>=0)
469  {
470  bool notifyParent=false;
471  if(autostitch && m_projList.Item(i).target==Project::DETECTING)
472  {
473  wxFileName name(m_projList.Item(i).path);
474  AddProjectToBatch(m_projList.Item(i).path,name.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + name.GetName(), wxEmptyString, Project::STITCHING);
475  notifyParent=true;
476  };
477  if(autoremove)
478  {
480  SaveTemp();
481  notifyParent=true;
482  };
483  if(notifyParent)
484  {
485  wxCommandEvent e(EVT_UPDATE_PARENT,wxID_ANY);
486  GetParent()->GetEventHandler()->AddPendingEvent(e);
487  };
488  };
489  }
490  if(!m_cancelled && !m_paused)
491  {
492  if(AllDone())
493  {
494  SaveTemp();
495  m_running = false;
496 #if wxCHECK_VERSION(3,1,0)
497  if (m_resBlocker != NULL)
498  {
499  delete m_resBlocker;
500  m_resBlocker = NULL;
501  };
502 #endif
503  if(NoErrors())
504  {
505  wxCommandEvent e(EVT_INFORMATION,wxID_ANY);
506  e.SetString(_("Batch successfully completed."));
507  // setting int to 1 to indicate we are finished
508  e.SetInt(1);
509  GetParent()->GetEventHandler()->AddPendingEvent(e);
510  }
511  else
512  {
513  ((wxFrame*)GetParent())->SetStatusText(_("Batch completed with errors."));
514  if(atEnd==DO_NOTHING)
515  {
516  //notify parent, that at least one project failed
517  // show dialog only if we don't shutdown the computer or end PTBatcherGUI
518  wxCommandEvent e(EVT_BATCH_FAILED,wxID_ANY);
519  GetParent()->GetEventHandler()->AddPendingEvent(e);
520  };
521  };
522  switch (atEnd)
523  {
524  case DO_NOTHING:
525  // no action needed
526  break;
527  case CLOSE_PTBATCHERGUI:
528  GetParent()->Close();
529  break;
530  case SHUTDOWN:
531  {
532  wxProgressDialog progress(_("Initializing shutdown..."), _("Shutting down..."), 49, this,
533  wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_CAN_SKIP);
534  progress.Fit();
535  int i = 0;
536  bool skip = false;
537  while (progress.Update(i, _("Shutting down..."), &skip))
538  {
539  if (skip || i == 50)
540  {
541  wxShutdown(wxSHUTDOWN_POWEROFF);
542  }
543  i++;
544 #if defined __WXMSW__
545  Sleep(200);
546 #else
547  sleep(200);
548 #endif
549  }
550  progress.Close();
551  }
552  break;
553  case SUSPEND:
554  case HIBERNATE:
555 #ifdef __WXMSW__
556  {
557  wxString progressCaption(_("Prepare to hibernate..."));
558  wxString progressLabel(_("Initializing hibernating..."));
559  if (atEnd == SUSPEND)
560  {
561  progressCaption = wxString(_("Prepare to suspend..."));
562  progressLabel = wxString(_("Initializing suspend mode..."));
563  };
564  wxProgressDialog progress(progressLabel, progressCaption, 49, this,
565  wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_CAN_SKIP);
566  progress.Fit();
567  int i = 0;
568  bool skip = false;
569  while (progress.Update(i, progressCaption, &skip))
570  {
571  if (skip || i == 50)
572  {
573  SetSuspendState(atEnd==HIBERNATE, false, false);
574  break;
575  }
576  i++;
577  Sleep(200);
578  }
579  progress.Close();
580  };
581 #endif
582  break;
583  };
584  }
585  else
586  {
587  RunNextInBatch();
588  }
589  }
590  else
591  {
592  //after all processes have ended on a cancel, we reset the boolean back to false
593  //if(stitchFrames.GetCount()==0)
594  if(GetRunningCount()==0)
595  {
596  m_cancelled=false;
597  }
598  }
599  }
600 }
601 
602 bool Batch::OnStitch(wxString scriptFile, wxString outname, wxString userDefinedOutput, int id)
603 {
604  // delete the existing wxConfig to force reloading of settings from file/registy
605  delete wxConfigBase::Set((wxConfigBase*)NULL);
606  wxConfigBase* config = wxConfigBase::Get();
607  if(wxIsEmpty(scriptFile))
608  {
609  wxString defaultdir = config->Read(wxT("/actualPath"),wxT(""));
610  wxFileDialog dlg(0,
611  _("Specify project file"),
612  defaultdir, wxT(""),
613  _("Project files (*.pto)|*.pto|All files (*)|*"),
614  wxFD_OPEN, wxDefaultPosition);
615 
616  dlg.SetDirectory(wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")));
617  if (dlg.ShowModal() == wxID_OK)
618  {
619  config->Write(wxT("/actualPath"), dlg.GetDirectory()); // remember for later
620  config->Flush();
621  wxFileDialog dlg2(0,_("Specify output prefix"),
622  wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")),
623  wxT(""), wxT(""),
624  wxFD_SAVE, wxDefaultPosition);
625  dlg2.SetDirectory(wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")));
626  if (dlg2.ShowModal() == wxID_OK)
627  {
628  outname = dlg2.GetPath();
629  }
630  else // bail
631  {
632  wxLogError( _("No output prefix specified"));
633  return false;
634  }
635  scriptFile = dlg.GetPath();
636  }
637  else // bail
638  {
639  wxLogError(_("No project files specified"));
640  return false;
641  }
642  }
643 
644  // check output filename
645  wxFileName outfn(outname);
646  wxString ext = outfn.GetExt();
647  // remove extension if it indicates an image file
648  if (ext.CmpNoCase(wxT("jpg")) == 0 || ext.CmpNoCase(wxT("jpeg")) == 0 ||
649  ext.CmpNoCase(wxT("tif")) == 0 || ext.CmpNoCase(wxT("tiff")) == 0 ||
650  ext.CmpNoCase(wxT("png")) == 0 || ext.CmpNoCase(wxT("exr")) == 0 ||
651  ext.CmpNoCase(wxT("pnm")) == 0 || ext.CmpNoCase(wxT("hdr")) == 0)
652  {
653  outfn.ClearExt();
654  outname = outfn.GetFullPath();
655  }
656 
657  RunStitchFrame* stitchFrame = new RunStitchFrame(this, wxT("Hugin Stitcher"), wxDefaultPosition, wxSize(640,600));
658  stitchFrame->SetProjectId(id);
659  if(verbose)
660  {
661  stitchFrame->Show( true );
662  wxTheApp->SetTopWindow( stitchFrame );
663  }
664 
665  wxFileName basename(scriptFile);
666  stitchFrame->SetTitle(wxString::Format(_("%s - Stitching"), basename.GetName().c_str()));
667  if(overwrite)
668  {
669  stitchFrame->m_stitchPanel->SetOverwrite(true);
670  }
671 
672  bool n = stitchFrame->StitchProject(scriptFile, outname, userDefinedOutput);
673  if(n)
674  {
675  m_stitchFrames.Add(stitchFrame);
676  }
677  else
678  {
679  stitchFrame->Close();
680  }
681  return n;
682 
683 }
684 
685 bool Batch::OnDetect(wxString scriptFile, wxString userDefinedAssistant, int id)
686 {
687  // delete the existing wxConfig to force reloading of settings from file/registy
688  delete wxConfigBase::Set((wxConfigBase*)NULL);
689  RunStitchFrame* stitchFrame = new RunStitchFrame(this, wxT("Hugin Assistant"), wxDefaultPosition, wxSize(640, 600));
690  stitchFrame->SetProjectId(id);
691  if(verbose)
692  {
693  stitchFrame->Show( true );
694  wxTheApp->SetTopWindow( stitchFrame );
695  }
696 
697  wxFileName basename(scriptFile);
698  stitchFrame->SetTitle(wxString::Format(_("%s - Assistant"), basename.GetName().c_str()));
699 
700  bool n = stitchFrame->DetectProject(scriptFile, userDefinedAssistant);
701  if(n)
702  {
703  m_stitchFrames.Add(stitchFrame);
704  }
705  else
706  {
707  stitchFrame->Close();
708  }
709  return n;
710 
711 }
712 
714 {
715  if(!m_paused)
716  {
717  m_paused = true;
718  for(int i=0; i<GetRunningCount(); i++)
719  {
720  m_stitchFrames.Item(i)->m_stitchPanel->PauseStitch();
721  }
722  for(unsigned int i=0; i<m_projList.GetCount(); i++)
723  {
724  if(m_projList.Item(i).status==Project::RUNNING)
725  {
726  m_projList.Item(i).status=Project::PAUSED;
727  }
728  }
729  }
730  else
731  {
732  m_paused = false;
733  for(int i=0; i<GetRunningCount(); i++)
734  {
735  m_stitchFrames.Item(i)->m_stitchPanel->ContinueStitch();
736  }
737  for(unsigned int i=0; i<m_projList.GetCount(); i++)
738  {
739  if(m_projList.Item(i).status==Project::PAUSED)
740  {
741  m_projList.Item(i).status=Project::RUNNING;
742  }
743  }
744  }
745 }
746 
748 {
749  if(GetIndex(id) != -1)
750  {
752  }
753  else
754  {
755  wxMessageBox(wxString::Format(_("Error removing, project with id %d is not in list."),id),_("Error!"),wxOK | wxICON_INFORMATION );
756  }
757 }
758 
759 void Batch::RemoveProjectAtIndex(int selIndex)
760 {
761  //we delete only successful project files and no applications
762  if(deleteFiles
763  && m_projList.Item(selIndex).id>=0
764  && m_projList.Item(selIndex).status==Project::FINISHED)
765  {
766  wxFileName file(m_projList.Item(selIndex).path);
767  if(file.FileExists())
768  {
769  if(!wxRemoveFile(file.GetFullPath()))
770  {
771  wxMessageBox(wxString::Format(_("Error: Could not delete project file %s"), file.GetFullPath()),_("Error!"),wxOK | wxICON_INFORMATION );
772  }
773  }
774  }
775  m_projList.RemoveAt(selIndex);
776  if(m_projList.GetCount()==0) //reset the id generator on empty list
777  {
779  }
780 }
781 
783 {
784  if(!m_running)
785  {
786  m_failedProjects.clear();
787  ((wxFrame*)GetParent())->SetStatusText(_("Running batch..."));
788  m_running = true;
789 #if wxCHECK_VERSION(3,1,0)
790  m_resBlocker = new wxPowerResourceBlocker(wxPOWER_RESOURCE_SYSTEM, _("PTBatcherGUI is stitching"));
791 #endif
792  RunNextInBatch();
793  }
794  else
795  {
796  ((wxFrame*)GetParent())->SetStatusText(_("Batch already in progress."));
797  }
798 }
799 
801 {
802  bool value;
803  bool repeat = true;
804  int i;
805  while(((i=GetFirstAvailable())!=-1) && repeat)
806  {
807  //execute command line instructions
808  if(m_projList.Item(i).id<0)
809  {
810  SetStatusText(wxString::Format(_("Running command \"%s\""), m_projList.Item(i).path.c_str()));
811  m_projList.Item(i).status=Project::RUNNING;
812  //we create a fake stitchFrame, so program waits for app to complete
813  if(wxExecute(m_projList.Item(i).path, wxEXEC_SYNC)==0)
814  {
815  m_projList.Item(i).status=Project::FINISHED;
816  }
817  else
818  {
819  m_projList.Item(i).status=Project::FAILED;
820  }
821  }
822  else
823  {
824  if (m_projList.Item(i).status == Project::MISSING)
825  {
826  // skip non-existing project files
827  continue;
828  };
829  if (!m_projList.Item(i).userDefindSequence.empty())
830  {
831  // skip non-existing user defined sequence files
832  if (!wxFileName::FileExists(m_projList.Item(i).userDefindSequence))
833  {
834  m_projList.Item(i).status = Project::MISSING;
835  m_projList.Item(i).skip = true;
836  continue;
837  };
838  }
839  m_projList.Item(i).status=Project::RUNNING;
840  m_running = true;
841  if(m_projList.Item(i).target==Project::STITCHING)
842  {
843  wxCommandEvent e(EVT_INFORMATION,wxID_ANY);
844  e.SetString(wxString::Format(_("Now stitching: %s"),m_projList.Item(i).path.c_str()));
845  GetParent()->GetEventHandler()->AddPendingEvent(e);
846  value = OnStitch(m_projList.Item(i).path, m_projList.Item(i).prefix, m_projList.Item(i).userDefindSequence, m_projList.Item(i).id);
847  }
848  else
849  {
850  wxCommandEvent e(EVT_INFORMATION,wxID_ANY);
851  e.SetString(wxString::Format(_("Now detecting: %s"),m_projList.Item(i).path.c_str()));
852  GetParent()->GetEventHandler()->AddPendingEvent(e);
853  value = OnDetect(m_projList.Item(i).path, m_projList.Item(i).userDefindSequence, m_projList.Item(i).id);
854  };
855  if(!value)
856  {
857  m_projList.Item(i).status=Project::FAILED;
858  }
859  else
860  {
861  repeat = false;
862  }
863  }
864  }
865  if(AllDone())
866  {
867  m_running = false;
868  }
869 }
870 
871 void Batch::SaveBatchFile(wxString file)
872 {
873  wxFileConfig batchFile;
874  //we write current idGenerator to file
875  batchFile.Write("/Main/CurrentID", Project::idGenerator);
876  batchFile.Write("/Main/Count", m_projList.GetCount());
877  //then for each project: project path, prefix, id, status, skip
878  for (unsigned int i = 0; i < m_projList.GetCount(); i++)
879  {
880  batchFile.SetPath(wxString::Format("/Project_%u", i + 1));
881  batchFile.Write("Project", m_projList.Item(i).path);
882  switch (m_projList.Item(i).target)
883  {
884  case Project::STITCHING:
885  batchFile.Write("Type", "Stitching");
886  batchFile.Write("Prefix", m_projList.Item(i).prefix);
887  break;
888  case Project::DETECTING:
889  batchFile.Write("Type", "Detecting");
890  break;
891  };
892  if (!m_projList.Item(i).userDefindSequence.IsEmpty())
893  {
894  batchFile.Write("UserDefinedSequence", m_projList.Item(i).userDefindSequence);
895  };
896  batchFile.Write("Id", m_projList.Item(i).id);
897  batchFile.Write("Status", (long)m_projList.Item(i).status);
898  if (m_projList.Item(i).skip)
899  {
900  batchFile.Write("Skip", m_projList.Item(i).skip);
901  };
902  };
903  wxFileOutputStream fileStream(file);
904  batchFile.Save(fileStream);
905  fileStream.Close();
906 }
907 
909 {
910  wxString userDataDir = wxString(hugin_utils::GetUserAppDataDir().c_str(), wxConvLocal);
911  if (userDataDir.IsEmpty())
912  {
913  // could not find user data directory, or this directory could not be create
914  // fall back to system user data dir
915  userDataDir = wxStandardPaths::Get().GetUserConfigDir();
916  }
917  return wxFileName(userDataDir, _T("PTBatcherQueue.ptq")).GetFullPath();
918 }
919 
921 {
923 }
924 
925 void Batch::SetStatus(int index,Project::Status status)
926 {
927  if((unsigned int)index<m_projList.GetCount())
928  {
929  m_projList.Item(index).status = status;
930  }
931  else
932  {
933  wxMessageBox(wxString::Format(_("Error: Could not set status, project with index %d is not in list."),index),_("Error!"),wxOK | wxICON_INFORMATION );
934  }
935 }
936 
937 void Batch::SwapProject(int index)
938 {
939  Project* proj = m_projList.Detach(index+1);
940  m_projList.Insert(proj,index);
941 }
942 
943 void Batch::ShowOutput(bool isVisible)
944 {
945  for(unsigned int i=0; i<m_stitchFrames.Count(); i++)
946  {
947  m_stitchFrames.Item(i)->Show(isVisible);
948  };
949 };
950 
951 wxString Batch::GetFailedProjectName(unsigned int i)
952 {
953  if(i<m_failedProjects.size())
954  {
955  return m_failedProjects[i].project;
956  }
957  else
958  {
959  return wxEmptyString;
960  }
961 };
962 
963 wxString Batch::GetFailedProjectLog(unsigned int i)
964 {
965  if(i<m_failedProjects.size())
966  {
967  return m_failedProjects[i].logfile;
968  }
969  else
970  {
971  return wxEmptyString;
972  }
973 };
bool NoErrors()
Returns true if there are no failed projects in batch.
Definition: Batch.cpp:393
int GetRunningCount()
Returns number of projects currently in progress.
Definition: Batch.cpp:334
int ClearBatch()
Clears batch list and returns 0 if succesful.
Definition: Batch.cpp:235
int GetFirstAvailable()
Returns index of first waiting project in batch.
Definition: Batch.cpp:274
bool FileExists(const std::string &filename)
checks if file exists
Definition: utils.cpp:362
void SwapProject(int index)
Swaps position in batch of project at index with project at index+1.
Definition: Batch.cpp:937
void RemoveProjectAtIndex(int selIndex)
Removes project at index from batch list.
Definition: Batch.cpp:759
int GetProjectCount()
Returns number of projects in batch list.
Definition: Batch.cpp:316
bool verbose
Definition: Batch.h:62
FrameArray m_stitchFrames
Definition: Batch.h:162
bool deleteFiles
Definition: Batch.h:59
RunStitchPanel * m_stitchPanel
int GetIndex(int id)
Returns index of project with selected id.
Definition: Batch.cpp:299
bool saveLog
Definition: Batch.h:65
void SetStatus(int index, Project::Status status)
Used internally to set status of selected project.
Definition: Batch.cpp:925
void CancelBatch()
Stops batch run, failing projects in progress.
Definition: Batch.cpp:196
bool autostitch
Definition: Batch.h:63
END_EVENT_TABLE()
bool OnDetect(wxString scriptFile, wxString userDefinedAssistant, int id)
called to start detecting
Definition: Batch.cpp:685
void RemoveProject(int id)
Removes project with id from batch list.
Definition: Batch.cpp:747
void AddProjectToBatch(wxString projectFile, wxString outputFile=wxEmptyString, wxString userDefinedSequence=wxEmptyString, Project::Target target=Project::STITCHING)
Adds a project entry in the batch list.
Definition: Batch.cpp:92
void AddAppToBatch(wxString app)
Adds an application entry in the batch list.
Definition: Batch.cpp:86
bool StitchProject(wxString scriptFile, wxString outname, wxString userDefinedOutput=wxEmptyString)
Starts stitching of project file.
int LoadBatchFile(wxString file)
Clears current batch list and loads projects from batch file.
Definition: Batch.cpp:362
bool IsPaused()
Returns true if batch execution is currently paused.
Definition: Batch.cpp:357
void ChangePrefix(int index, wxString newPrefix)
Changes output prefix for project at index.
Definition: Batch.cpp:225
void AppendBatchFile(wxString file)
Appends projects from file to batch list.
Definition: Batch.cpp:126
bool DetectProject(wxString scriptFile, wxString userDefinedAssistant=wxEmptyString)
starts assistant of project file
Project::Status GetStatus(int index)
Returns current status of project at index.
Definition: Batch.cpp:339
bool IsRunning()
return true, if batch is running
Definition: Batch.cpp:352
void RunNextInBatch()
Starts execution of next waiting project in batch.
Definition: Batch.cpp:800
wxString GetFailedProjectName(unsigned int i)
returns project file name of failed project with index i
Definition: Batch.cpp:951
void PauseBatch()
Pauses and continues batch execution.
Definition: Batch.cpp:713
ProjectArray m_projList
Definition: Batch.h:160
EndTask atEnd
Definition: Batch.h:60
bool m_paused
Definition: Batch.h:166
void SaveTemp()
Saves batch list to temporary file.
Definition: Batch.cpp:920
Project * GetProject(int index)
Returns project at index.
Definition: Batch.cpp:311
Definition: Batch.h:48
void ShowOutput(bool isVisible=true)
Set visibility of all running projects.
Definition: Batch.cpp:943
bool m_cancelled
Definition: Batch.h:165
wxString project
Definition: Batch.h:44
int GetProjectCountByPath(wxString path)
Returns number of projects in batch list with the input file path.
Definition: Batch.cpp:321
void RunBatch()
Starts batch execution.
Definition: Batch.cpp:782
bool m_clearedInProgress
Definition: Batch.h:168
std::vector< FailedProject > m_failedProjects
Definition: Batch.h:171
bool autoremove
Definition: Batch.h:64
static long idGenerator
Definition: ProjectArray.h:61
Batch(wxFrame *parent)
Main constructor.
Definition: Batch.cpp:57
void SetOverwrite(bool over=true)
void CancelProject(int index)
Cancels project at index in batch, failing it.
Definition: Batch.cpp:212
void SaveBatchFile(wxString file)
Saves batch list to file.
Definition: Batch.cpp:871
bool CompareProjectsInLists(int stitchListIndex, int batchListIndex)
Compares two project at indexes in both lists and returns true if they have identical project ids...
Definition: Batch.cpp:269
std::string GetUserAppDataDir()
returns the directory for user specific Hugin settings, e.g.
Definition: utils.cpp:497
wxString GetBatchFilename()
returns the filename of the default queue file
Definition: Batch.cpp:908
bool m_running
Definition: Batch.h:167
bool AllDone()
Returns true if there are no more projects pending execution.
Definition: Batch.cpp:112
Batch processor for Hugin.
void SetProjectId(int id)
Sets project id from batch.
void OnProcessTerminate(wxProcessEvent &event)
Called internally when all running processes have completed and need to be removed from running list...
Definition: Batch.cpp:405
~Batch()
destructor
Definition: Batch.cpp:76
wxString GetFailedProjectLog(unsigned int i)
returns log file name of failed project with index i
Definition: Batch.cpp:963
bool overwrite
Definition: Batch.h:61
int LoadTemp()
Loads temporary batch file.
Definition: Batch.cpp:382
wxString logfile
Definition: Batch.h:45
bool OnStitch(wxString scriptFile, wxString outname, wxString userDefinedOutput, int id)
Called to start stitch of project with input scriptFile.
Definition: Batch.cpp:602
void ChangeUserDefined(int index, wxString newUserDefined)
Changes user defined sequence for project at index.
Definition: Batch.cpp:230