1 /////////////////////////////////////////////////////////////////////////////
2 // Name: ProgressDlg.cpp
3 // Author: Alex Thuering
4 // Created: 14.08.2004
5 // RCS-ID: $Id: ProgressDlg.cpp,v 1.182 2016/12/11 10:06:31 ntalex Exp $
6 // Copyright: (c) Alex Thuering
7 // Licence: GPL
8 /////////////////////////////////////////////////////////////////////////////
9
10 #include "ProgressDlg.h"
11 #include "MainWin.h"
12 #include "BurnDlg.h"
13 #include "DVD.h"
14 #include "Cache.h"
15 #include "ProcessCleanTemp.h"
16 #include "ProcessProjectInfo.h"
17 #include "ProcessMenu.h"
18 #include "ProcessMenuTransitions.h"
19 #include "ProcessEncode.h"
20 #include "ProcessSlideshow.h"
21 #include "ProcessSubtitles.h"
22 #include "ProcessDvdFilesystem.h"
23 #include "ProcessPreview.h"
24 #include "ProcessIsoImage.h"
25 #include "ProcessEccData.h"
26 #include "ProcessFormatDvd.h"
27 #include "ProcessBurn.h"
28 #include "mediaenc_ffmpeg.h"
29 #include "Config.h"
30 #include "SysUtils.h"
31 #include "Version.h"
32 #include <wxVillaLib/utils.h>
33 #include <wx/filename.h>
34
35 //(*InternalHeaders(ProgressDlg)
36 #include <wx/intl.h>
37 #include <wx/string.h>
38 //*)
39
40 class ProcessLog: public wxLog {
41 public:
42 /** Constructor */
ProcessLog(ProgressDlg * progressDlg)43 ProcessLog(ProgressDlg* progressDlg) {
44 this->m_progressDlg = progressDlg;
45 }
46 protected:
47 /** Print the message into progress dialog details window. */
DoLog(wxLogLevel level,const wxChar * szString,time_t t)48 void DoLog(wxLogLevel level, const wxChar* szString, time_t t) {
49 m_progressDlg->AddDetailMsg(szString, level <= wxLOG_Error ? *wxRED : wxColour(64,64,64));
50 }
51 private:
52 ProgressDlg* m_progressDlg;
53 };
54
55 //(*IdInit(ProgressDlg)
56 const long ProgressDlg::ID_SUMMURY_CTRL = wxNewId();
57 const long ProgressDlg::ID_GAUGE1 = wxNewId();
58 const long ProgressDlg::ID_DETAILS_CTRL = wxNewId();
59 const long ProgressDlg::ID_DETAILS_BT = wxNewId();
60 const long ProgressDlg::ID_CHECKBOX1 = wxNewId();
61 const long ProgressDlg::ID_MINIMIZE_BT = wxNewId();
62 //*)
63
BEGIN_EVENT_TABLE(ProgressDlg,wxDialog)64 BEGIN_EVENT_TABLE(ProgressDlg,wxDialog)
65 //(*EventTable(ProgressDlg)
66 //*)
67 END_EVENT_TABLE()
68
69 ProgressDlg::ProgressDlg(MainWin* parent, Cache* cache, bool autoStart) {
70 //(*Initialize(ProgressDlg)
71 wxStaticText* summaryLabel;
72 wxBoxSizer* btSizer;
73 wxBoxSizer* mainSizer;
74
75 Create(parent, wxID_ANY, _("Generate DVD"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER, _T("wxID_ANY"));
76 SetClientSize(wxSize(600,600));
77 mainSizer = new wxBoxSizer(wxVERTICAL);
78 m_panelSizer = new wxBoxSizer(wxVERTICAL);
79 summaryLabel = new wxStaticText(this, wxID_ANY, _("Summary:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
80 m_panelSizer->Add(summaryLabel, 0, wxBOTTOM|wxALIGN_LEFT, 2);
81 m_summaryText = new wxTextCtrl(this, ID_SUMMURY_CTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH, wxDefaultValidator, _T("ID_SUMMURY_CTRL"));
82 m_panelSizer->Add(m_summaryText, 1, wxBOTTOM|wxEXPAND, 8);
83 m_gauge = new wxGauge(this, ID_GAUGE1, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL|wxGA_SMOOTH, wxDefaultValidator, _T("ID_GAUGE1"));
84 m_panelSizer->Add(m_gauge, 0, wxBOTTOM|wxEXPAND, 4);
85 m_detailsLabel = new wxStaticText(this, wxID_ANY, _("Details:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
86 m_panelSizer->Add(m_detailsLabel, 0, wxBOTTOM|wxALIGN_LEFT, 2);
87 m_detailsText = new wxTextCtrl(this, ID_DETAILS_CTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH, wxDefaultValidator, _T("ID_DETAILS_CTRL"));
88 m_panelSizer->Add(m_detailsText, 1, wxEXPAND, 0);
89 mainSizer->Add(m_panelSizer, 1, wxTOP|wxLEFT|wxRIGHT|wxEXPAND, 8);
90 btSizer = new wxBoxSizer(wxHORIZONTAL);
91 m_detailsBt = new wxButton(this, ID_DETAILS_BT, _("Hide details"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_DETAILS_BT"));
92 btSizer->Add(m_detailsBt, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
93 m_shutdown = new wxCheckBox(this, ID_CHECKBOX1, _("Turn off PC when finished"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_CHECKBOX1"));
94 m_shutdown->SetValue(false);
95 btSizer->Add(m_shutdown, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
96 btSizer->Add(-1,-1,1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
97 m_minimizeBt = new wxButton(this, ID_MINIMIZE_BT, _("Minimize"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_MINIMIZE_BT"));
98 btSizer->Add(m_minimizeBt, 0, wxRIGHT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 8);
99 m_cancelBt = new wxButton(this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("wxID_CANCEL"));
100 btSizer->Add(m_cancelBt, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
101 mainSizer->Add(btSizer, 0, wxALL|wxEXPAND, 8);
102 SetSizer(mainSizer);
103 SetSizer(mainSizer);
104 Layout();
105 Center();
106
107 Connect(ID_DETAILS_BT,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&ProgressDlg::OnHideDetails);
108 Connect(ID_CHECKBOX1,wxEVT_COMMAND_CHECKBOX_CLICKED,(wxObjectEventFunction)&ProgressDlg::OnShutdownClick);
109 Connect(ID_MINIMIZE_BT,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&ProgressDlg::OnMinimize);
110 Connect(wxID_CANCEL,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&ProgressDlg::OnCancel);
111 //*)
112
113 m_detailsBtLabel = m_detailsBt->GetLabel();
114 m_detailsBt->SetLabel(_T("<< ") + m_detailsBtLabel);
115 m_detailsText->SetFont(wxFont(8, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
116 m_winDisabler = NULL;
117
118 m_end = false;
119 m_close = false;
120 m_autoStart = autoStart;
121 m_cancel = false;
122 m_step = 0;
123 m_stepCount = 0;
124 m_subStep = 0;
125 m_subStepCount = 0;
126 m_cache = cache;
127
128 #if !defined(__WXMSW__) && !defined(HAVE_LIBDBUS)
129 m_shutdown->Enable(false);
130 #endif
131 }
132
~ProgressDlg()133 ProgressDlg::~ProgressDlg() {
134 //(*Destroy(ProgressDlg)
135 //*)
136 }
137
OnHideDetails(wxCommandEvent & event)138 void ProgressDlg::OnHideDetails(wxCommandEvent& event) {
139 if (m_detailsText->IsShown()) {
140 m_detailsLabel->Hide();
141 m_detailsText->Hide();
142 m_detailsText->Freeze();
143 m_panelSizer->Detach(m_detailsLabel);
144 m_panelSizer->Detach(m_detailsText);
145 int height = m_detailsLabel->GetSize().GetY() + m_detailsText->GetSize().GetY() + 2;
146 SetSize(GetSize().GetX(), GetSize().GetY() - height);
147 m_detailsBt->SetLabel(_("Show details") + wxString(_T(" >>")));
148 } else {
149 m_detailsLabel->Show();
150 m_detailsText->Show();
151 m_detailsText->Thaw();
152 m_panelSizer->Insert(3, m_detailsLabel, 0, wxBOTTOM, 2);
153 m_panelSizer->Insert(4, m_detailsText, 1, wxEXPAND, 0);
154 int height = m_detailsLabel->GetSize().GetY() + m_detailsText->GetSize().GetY() + 2;
155 SetSize(GetSize().GetX(), GetSize().GetY() + height);
156 m_detailsBt->SetLabel(_T("<< ") + m_detailsBtLabel);
157 }
158 }
159
OnMinimize(wxCommandEvent & event)160 void ProgressDlg::OnMinimize(wxCommandEvent& event) {
161 wxPlatformInfo info;
162 if ((info.GetOperatingSystemId() & wxOS_WINDOWS) && !info.CheckOSVersion(6,0))
163 wxDELETE(m_winDisabler);
164 ((wxFrame*) GetParent())->Iconize();
165 }
166
OnCancel(wxCommandEvent & event)167 void ProgressDlg::OnCancel(wxCommandEvent& event) {
168 if (!WasCanceled() && !m_end) {
169 Cancel();
170 } else {
171 m_close = true;
172 ((MainWin*) this->GetParent())->SetProgressBarValue(0, 100);
173 ((MainWin*) this->GetParent())->SetProgressBarState();
174 }
175 }
176
177 /** Adds the given message to summary textbox */
AddSummaryMsg(const wxString & message,const wxString & details,const wxColour & colour)178 void ProgressDlg::AddSummaryMsg(const wxString& message, const wxString& details, const wxColour& colour) {
179 m_summaryText->SetDefaultStyle(wxTextAttr(colour.Ok() ? colour : *wxBLACK));
180 m_summaryText->AppendText(message + _T("\n"));
181 m_summaryText->ShowPosition(m_summaryText->GetLastPosition());
182 AddDetailMsg(details.length() ? details : message, colour.Ok() ? colour : *wxBLACK);
183 m_lastSummaryMsg = message;
184 }
185
186 /** Replaces last line with the given text in details textbox */
ReplaceSummaryMsg(const wxString & message)187 void ProgressDlg::ReplaceSummaryMsg(const wxString& message) {
188 long lastPos = m_summaryText->GetLastPosition();
189 m_summaryText->Replace(lastPos - m_lastSummaryMsg.length() - 1, lastPos + 1, message + wxT("\n"));
190 m_summaryText->ShowPosition(m_summaryText->GetLastPosition());
191 wxYieldIfNeeded();
192 m_lastSummaryMsg = message;
193 }
194
195 /** Add the given message to details textbox */
AddDetailMsg(const wxString & message,const wxColour & colour)196 void ProgressDlg::AddDetailMsg(const wxString& message, const wxColour& colour) {
197 if (m_cancel)
198 return;
199 if (colour.Ok())
200 m_detailsText->SetDefaultStyle(wxTextAttr(colour));
201 AddDetailText(message + _T("\n"));
202 m_detailsText->SetDefaultStyle(wxTextAttr(wxColour(64, 64, 64)));
203 }
204
205 /** Replaces last message with the given message in details textbox */
ReplaceLastDetailMsg(const wxString & message)206 void ProgressDlg::ReplaceLastDetailMsg(const wxString& message) {
207 ReplaceLastDetailText(message + _T("\n"));
208 }
209
210 /** Add the given text to details textbox */
AddDetailText(const wxString & text)211 void ProgressDlg::AddDetailText(const wxString& text) {
212 if (wxLog::GetActiveTarget()->GetVerbose())
213 fprintf(stderr, "%s", (const char*) text.mb_str());
214 m_logFile.Write(text);
215 m_logFile.Flush();
216 m_detailsText->AppendText(text);
217 m_detailsText->ShowPosition(m_detailsText->GetLastPosition());
218 wxYieldIfNeeded();
219 if (text.StartsWith(wxT("Encoding Mode:"))) {
220 wxString mode = text.Mid(15);
221 int len = mode.Find(wxT("HQ"));
222 if (len > 0)
223 mode = mode.Mid(0, len).Strip();
224 else
225 mode = mode.BeforeFirst(wxT(' '));
226 if (mode.length() == 0)
227 mode = _("Copy");
228 int pos = m_lastSummaryMsg.Find(_("Encoding Mode"));
229 if (pos > 0) {
230 ReplaceSummaryMsg(m_lastSummaryMsg.Mid(0, pos + 15) + mode + wxT(")"));
231 } else {
232 ReplaceSummaryMsg(m_lastSummaryMsg + wxT(" (") + _("Encoding Mode") + wxT(": ") + mode + wxT(")"));
233 }
234 }
235 m_lastDetailText = text;
236 }
237
238 /** Replaces last line with the given text in details textbox */
ReplaceLastDetailText(const wxString & text)239 void ProgressDlg::ReplaceLastDetailText(const wxString& text) {
240 if (wxLog::GetActiveTarget()->GetVerbose())
241 fprintf(stderr, "%s", (const char*) text.mb_str());
242 long lastPos = m_detailsText->GetLastPosition();
243 m_detailsText->Replace(lastPos - m_lastDetailText.length(), lastPos + 1, text);
244 m_detailsText->ShowPosition(m_detailsText->GetLastPosition());
245 wxYieldIfNeeded();
246 m_lastDetailText = text;
247 }
248
249 /** Sets the step count of generating process */
SetSteps(int stepCount)250 void ProgressDlg::SetSteps(int stepCount) {
251 m_stepCount = stepCount;
252 m_step = 0;
253 InitGauge(stepCount*100);
254 }
255
UpdateGauge()256 void ProgressDlg::UpdateGauge() {
257 int subStep = 0;
258 if (m_subStepCount > 0 && m_subStep > m_subStepCount)
259 m_subStep = m_subStepCount;
260 if (m_subStepCount > 0)
261 subStep = m_subStep * 100 / m_subStepCount;
262 int step = m_step * 100 + subStep;
263 m_gauge->SetValue(step);
264 ((MainWin*) this->GetParent())->SetProgressBarValue(step, m_stepCount * 100);
265 }
266
267 /** Initializes gauge */
InitGauge(int range)268 void ProgressDlg::InitGauge(int range) {
269 m_gauge->SetRange(range);
270 ((MainWin*) this->GetParent())->SetProgressBarState();
271 }
272
Failed(const wxString & message)273 void ProgressDlg::Failed(const wxString& message) {
274 AddSummaryMsg(_("Failed"), message, *wxRED);
275 ((MainWin*) this->GetParent())->SetProgressBarState(true);
276 }
277
End()278 void ProgressDlg::End() {
279 if (!WasCanceled())
280 wxBell();
281 m_cancelBt->SetLabel(_("Close"));
282 }
283
WasCanceled()284 bool ProgressDlg::WasCanceled() {
285 wxYieldIfNeeded();
286 return m_cancel;
287 }
288
289 /** Cancel the process */
Cancel()290 void ProgressDlg::Cancel() {
291 AddSummaryMsg(_("Aborted"), wxEmptyString, *wxRED);
292 m_cancel = true;
293 }
294
Start(BurnDlg * burnDlg,DVD * dvd)295 bool ProgressDlg::Start(BurnDlg* burnDlg, DVD* dvd) {
296 // disable parent window
297 m_winDisabler = new wxWindowDisabler(this);
298 // show dialog
299 Show();
300 // start
301 wxLog* previousLog = wxLog::SetActiveTarget(new ProcessLog(this));
302 // start
303 Run(burnDlg, dvd);
304 // end
305 End();
306 m_logFile.Close();
307 // restore log
308 delete wxLog::SetActiveTarget(previousLog);
309 m_end = true;
310 // close the Window or release the controls
311 if (m_autoStart) {
312 Close(true);
313 } else {
314 while (!m_close) {
315 wxMilliSleep(100);
316 wxYield();
317 }
318 }
319 wxDELETE(m_winDisabler);
320 return !m_cancel;
321 }
322
Run(BurnDlg * burnDlg,DVD * dvd)323 void ProgressDlg::Run(BurnDlg* burnDlg, DVD* dvd) {
324 if (WasCanceled())
325 return;
326
327 // check if libav or ffmpeg is present
328 #ifdef __WXMSW__
329 if ((!wxFileExists(wxGetAppPath() + s_config.GetAVConvCmd() + wxT(".exe"))
330 && !wxFileExists(wxGetAppPath() + s_config.GetAVConvCmd()))
331 || s_config.GetAVConvCmd() == wxT("ffmpeg-vbr")) {
332 if (wxFileExists(wxGetAppPath() + wxT("avconv.exe")))
333 s_config.SetAVConvCmd(wxT("avconv"));
334 else if (wxFileExists(wxGetAppPath() + wxT("ffmpeg.exe")))
335 s_config.SetAVConvCmd(wxT("ffmpeg"));
336 }
337 #endif
338
339 wxString tmpDir = burnDlg->GetTempDir();
340 if (tmpDir.Last() != wxFILE_SEP_PATH)
341 tmpDir += wxFILE_SEP_PATH;
342 wxString dvdTmpDir = tmpDir + wxString(wxT("dvd-tmp")) + wxFILE_SEP_PATH;
343 wxString dvdOutDir = tmpDir + wxString(wxT("dvd-out")) + wxFILE_SEP_PATH;
344 if (burnDlg->DoGenerate()) {
345 dvdOutDir = burnDlg->GetOutputDir();
346 if (dvdOutDir.Last() != wxFILE_SEP_PATH)
347 dvdOutDir += wxFILE_SEP_PATH;
348 }
349
350 // create log file
351 m_logFile.Open(tmpDir + wxT("dvdstyler.log"), wxT("w"));
352
353 // print version
354 AddDetailMsg(wxT("DVDStyler v") + APP_VERSION);
355 AddDetailMsg(wxGetOsDescription());
356 AddDetailMsg((s_config.GetAVConvCmd() == wxT("ffmpeg") ? wxT("FFmpeg: ") : wxT("Libav: "))
357 + wxFfmpegMediaEncoder::GetBackendVersion());
358
359 // prepare
360 AddSummaryMsg(_("Prepare"));
361
362 // clean temp dir
363 ProcessCleanTemp cleanTemp(this, tmpDir, dvdTmpDir, dvdOutDir);
364 if (!cleanTemp.Execute())
365 return;
366
367 // check cache and calculate steps
368 AddDetailMsg(_("Search for transcoded files in cache"));
369 m_cache->BeginClean();
370
371 // processes
372 vector<Process*> processes;
373 processes.push_back(new ProcessProjectInfo(this, dvd)); // project info
374 processes.push_back(new ProcessMenu(this, dvd, dvdTmpDir)); // menus
375 processes.push_back(new ProcessEncode(this, dvd, m_cache, dvdTmpDir)); // titles
376 processes.push_back(new ProcessSlideshow(this, dvd, dvdTmpDir)); // slideshow
377 processes.push_back(new ProcessSubtitles(this, dvd, m_cache, dvdTmpDir)); // subtitle
378 processes.push_back(new ProcessMenuTransitions(this, dvd, dvdTmpDir)); // menu transitions
379 processes.push_back(new ProcessDvdFilesystem(this, dvd, dvdTmpDir, dvdOutDir));
380 processes.push_back(new ProcessPreview(this, burnDlg, dvdOutDir));
381 processes.push_back(new ProcessIsoImage(this, burnDlg, dvd, m_cache, dvdOutDir, tmpDir));
382 processes.push_back(new ProcessEccData(this, burnDlg, tmpDir));
383 processes.push_back(new ProcessFormatDvd(this, burnDlg));
384 processes.push_back(new ProcessBurn(this, burnDlg, dvd, dvdOutDir, tmpDir));
385
386 // remove unused files from cache
387 m_cache->EndClean();
388
389 // calculate step count
390 int stepCount = 0;
391 for (vector<Process*>::iterator it = processes.begin(); it != processes.end(); it++) {
392 Process* process = *it;
393 if (process->IsNeedExecute() && process->IsUpdateGauge())
394 stepCount++;
395 }
396 SetSteps(stepCount);
397
398 // Start generation
399 for (vector<Process*>::iterator it = processes.begin(); it != processes.end(); it++) {
400 Process* process = *it;
401 if (process->IsNeedExecute() && !process->Execute())
402 return;
403 }
404
405 if (WasCanceled())
406 return;
407
408 // clear temp directory
409 if (s_config.GetRemoveTempFiles())
410 cleanTemp.DeleteTempFiles(burnDlg->DoCreateIso() || burnDlg->DoBurn());
411
412 if (burnDlg->DoBurn())
413 AddSummaryMsg(_("Burning was successful."), wxEmptyString, wxColour(0, 128, 0));
414 else
415 AddSummaryMsg(_("Generating was successful."), wxEmptyString, wxColour(0, 128, 0));
416 wxLog::FlushActive();
417
418 if (DoShutdown()) {
419 SystemManager::Stop();
420 }
421 }
422
423
OnShutdownClick(wxCommandEvent & event)424 void ProgressDlg::OnShutdownClick(wxCommandEvent& event) {
425 if (event.IsChecked() && !SystemManager::CanStop()) {
426 wxMessageBox(wxT("You don't have the privileges to turn off the computer."),
427 wxTheApp->GetAppName(), wxICON_ERROR);
428 m_shutdown->SetValue(false);
429 }
430 }
431