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