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