1 /* QWinFF - a qt4 gui frontend for ffmpeg
2 * Copyright (C) 2011-2013 Timothy Lin <lzh9102@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "mainwindow.h"
19 #include "ui_mainwindow.h"
20 #include "convertlist.h"
21 #include "addtaskwizard.h"
22 #include "aboutffmpegdialog.h"
23 #include "optionsdialog.h"
24 #include "aboutdialog.h"
25 #include "poweroffdialog.h"
26 #include "updatedialog.h"
27 #include "services/paths.h"
28 #include "services/notification.h"
29 #include "services/powermanagement.h"
30 #include "converter/mediaconverter.h"
31 #include "converter/presets.h"
32 #include "services/updatechecker.h"
33 #include "services/constants.h"
34 #include "services/settingtimer.h"
35 #include "interactivecuttingdialog.h"
36 #include <QHBoxLayout>
37 #include <QToolButton>
38 #include <QMessageBox>
39 #include <QLabel>
40 #include <QFileDialog>
41 #include <QDesktopServices>
42 #include <QApplication>
43 #include <QSettings>
44 #include <QCloseEvent>
45 #include <QTimer>
46 #include <QSignalMapper>
47 #include <QPushButton>
48 #include <QDebug>
49 #include <QUrl>
50
51 #define DATA_PATH "/usr/local/share/qwinff"
52
MainWindow(QWidget * parent,const QStringList & fileList)53 MainWindow::MainWindow(QWidget *parent, const QStringList& fileList) :
54 QMainWindow(parent),
55 ui(new Ui::MainWindow),
56 m_presets(new Presets(this)),
57 m_list(new ConvertList(m_presets, this)),
58 m_argv_input_files(fileList),
59 m_elapsedTimeLabel(new QLabel(this)),
60 m_timer(new QTimer(this)),
61 m_poweroff_button(0),
62 m_poweroff_actiongroup(0),
63 m_update_checker(new UpdateChecker(this))
64 {
65 ui->setupUi(this);
66
67 connect(m_list, SIGNAL(task_finished(int)),
68 this, SLOT(task_finished(int)));
69 connect(m_list, SIGNAL(all_tasks_finished()),
70 this, SLOT(all_tasks_finished()));
71 connect(m_list, SIGNAL(customContextMenuRequested(QPoint)),
72 this, SLOT(slotListContextMenu(QPoint)));
73 connect(m_list, SIGNAL(itemSelectionChanged()),
74 this, SLOT(refresh_action_states()));
75 connect(m_timer, SIGNAL(timeout()),
76 this, SLOT(timerEvent()));
77 connect(m_list, SIGNAL(started()),
78 this, SLOT(conversion_started()));
79 connect(m_list, SIGNAL(stopped()),
80 this, SLOT(conversion_stopped()));
81 connect(m_update_checker, SIGNAL(receivedResult(int)),
82 this, SLOT(received_update_result(int)));
83 connect(ui->btnStartConversion, SIGNAL(clicked()),
84 this, SLOT(slotStartConversion()));
85
86 setup_widgets();
87 setup_menus();
88 setup_poweroff_button();
89 setup_toolbar(Constants::getSpaceSeparatedList("ToolbarEntries"));
90 setup_statusbar();
91 setup_appicon();
92
93 load_settings();
94
95 refresh_action_states();
96
97 if (!check_execute_conditions()) {
98 // Close the window immediately after it has started.
99 QTimer::singleShot(0, this, SLOT(close()));
100 } else {
101 QTimer::singleShot(0, this, SLOT(window_ready()));
102 }
103
104 }
105
~MainWindow()106 MainWindow::~MainWindow()
107 {
108 delete ui;
109 }
110
window_ready()111 void MainWindow::window_ready()
112 {
113 if (!m_argv_input_files.isEmpty()) {
114 add_files(m_argv_input_files);
115 }
116 QSettings settings;
117 if (settings.value("options/check_update_on_startup",
118 Constants::getBool("CheckUpdateOnStartup")).toBool()) {
119 if (ask_for_update_permission())
120 m_update_checker->checkUpdate();
121 }
122 refresh_status();
123 }
124
task_finished(int)125 void MainWindow::task_finished(int /*exitcode*/)
126 {
127 // if (exitcode == 0) { // succeed
128 // QMessageBox::information(this, this->windowTitle()
129 // , tr("Conversion finished successfully.")
130 // , QMessageBox::Ok);
131 // } else { // failed
132 // QMessageBox::critical(this, this->windowTitle()
133 // , tr("Conversion failed.")
134 // , QMessageBox::Ok);
135 // }
136 }
137
all_tasks_finished()138 void MainWindow::all_tasks_finished()
139 {
140 Notification::send(this, "QWinFF",
141 tr("All tasks have finished."), NotifyLevel::INFO);
142 activateWindow(); // notify the user (make taskbar entry blink)
143 refresh_action_states();
144
145 if (PowerManagement::implemented() && m_poweroff_button->isChecked()) {
146 // show poweroff dialog
147 if (PoweroffDialog(this).exec(get_poweroff_behavior()) == QDialog::Accepted) {
148 save_settings(); // save settings in case of power failure
149 }
150 }
151 }
152
153 // Menu Events
154
slotAddFiles()155 void MainWindow::slotAddFiles()
156 {
157 add_files();
158 }
159
slotOptions()160 void MainWindow::slotOptions()
161 {
162 OptionsDialog dialog(this);
163 dialog.exec();
164 }
165
slotSetTools()166 void MainWindow::slotSetTools()
167 {
168 OptionsDialog dialog(this);
169 dialog.exec_tools();
170 }
171
slotExit()172 void MainWindow::slotExit()
173 {
174 this->close();
175 }
176
slotStartConversion()177 void MainWindow::slotStartConversion()
178 {
179 if (m_list->isEmpty()) {
180 QMessageBox::information(this, this->windowTitle(),
181 tr("Nothing to convert."), QMessageBox::Ok);
182 } else {
183 m_list->start();
184 }
185 }
186
slotStopConversion()187 void MainWindow::slotStopConversion()
188 {
189 m_list->stop();
190 }
191
slotSetConversionParameters()192 void MainWindow::slotSetConversionParameters()
193 {
194 if (m_list->selectedCount() > 0) {
195 m_list->editSelectedParameters();
196 }
197 }
198
199 // Open the output folder of the file.
slotOpenOutputFolder()200 void MainWindow::slotOpenOutputFolder()
201 {
202 const ConversionParameters *param = m_list->getCurrentIndexParameter();
203 if (param) {
204 QString folder_path = QFileInfo(param->destination).path();
205 if (QFileInfo(folder_path).exists()) {
206 QDesktopServices::openUrl(QUrl::fromLocalFile(folder_path));
207 }
208 }
209 }
210
slotAboutQt()211 void MainWindow::slotAboutQt()
212 {
213 QMessageBox::aboutQt(this);
214 }
215
slotAboutFFmpeg()216 void MainWindow::slotAboutFFmpeg()
217 {
218 AboutFFmpegDialog(this).exec();
219 }
220
slotAbout()221 void MainWindow::slotAbout()
222 {
223 AboutDialog(this).exec();
224 }
225
slotShowUpdateDialog()226 void MainWindow::slotShowUpdateDialog()
227 {
228 if (ask_for_update_permission()) {
229 UpdateChecker update_checker;
230 UpdateDialog(this).exec(update_checker);
231 }
232 }
233
slotCut()234 void MainWindow::slotCut()
235 {
236 m_list->cutSelectedTask();
237 }
238
slotListContextMenu(QPoint)239 void MainWindow::slotListContextMenu(QPoint /*pos*/)
240 {
241 refresh_action_states();
242
243 QMenu menu;
244 menu.addAction(ui->actionOpenOutputFolder);
245 menu.addSeparator();
246 menu.addAction(ui->actionRemoveSelectedItems);
247 menu.addSeparator();
248 menu.addAction(ui->actionRetry);
249 menu.addAction(ui->actionRetryAll);
250 menu.addSeparator();
251 menu.addAction(ui->actionShowErrorMessage);
252 menu.addAction(ui->actionChangeOutputFilename);
253 menu.addAction(ui->actionChangeOutputDirectory);
254 menu.addAction(ui->actionSetParameters);
255 menu.addAction(ui->actionCut);
256
257 menu.exec(QCursor::pos());
258 }
259
260 // Events
261
closeEvent(QCloseEvent * event)262 void MainWindow::closeEvent(QCloseEvent *event)
263 {
264 if (m_list->isBusy()) {
265 int reply = QMessageBox::warning(this, this->windowTitle(),
266 tr("Conversion is still in progress. Abort?"),
267 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
268 if (reply == QMessageBox::No) {
269 event->ignore();
270 return;
271 }
272 }
273
274 m_list->stop();
275
276 save_settings();
277 }
278
timerEvent()279 void MainWindow::timerEvent()
280 {
281 refresh_status();
282 }
283
conversion_started()284 void MainWindow::conversion_started()
285 {
286 m_elapsedTimeLabel->clear();
287 m_timer->start(1000);
288 refresh_status();
289 refresh_action_states();
290 }
291
conversion_stopped()292 void MainWindow::conversion_stopped()
293 {
294 m_timer->stop();
295 refresh_status();
296 refresh_action_states();
297 }
298
update_poweroff_button(int id)299 void MainWindow::update_poweroff_button(int id)
300 {
301 const char *icon_id = "";
302 QString title = "";
303 QString status_tip = "";
304 switch (id) {
305 case PowerManagement::SHUTDOWN:
306 icon_id = ":/actions/icons/system_shutdown.png";
307 title = tr("Shutdown");
308 status_tip = tr("Shutdown when all tasks are done.");
309 break;
310 case PowerManagement::SUSPEND:
311 icon_id = ":/actions/icons/system_suspend.png";
312 title = tr("Suspend");
313 status_tip = tr("Suspend when all tasks are done.");
314 break;
315 case PowerManagement::HIBERNATE:
316 icon_id = ":/actions/icons/system_hibernate.png";
317 title = tr("Hibernate");
318 status_tip = tr("Hibernate when all tasks are done.");
319 break;
320 default:
321 Q_ASSERT(!"Incorrect id! Be sure to handle every power action in switch().");
322 }
323 m_poweroff_button->setIcon(QIcon(icon_id));
324 m_poweroff_button->setToolTip(status_tip);
325 m_poweroff_button->setStatusTip(status_tip);
326 ui->actionPoweroff->setIcon(QIcon(icon_id));
327 ui->actionPoweroff->setText(title);
328 ui->actionPoweroff->setStatusTip(status_tip);
329 }
330
received_update_result(int status)331 void MainWindow::received_update_result(int status)
332 {
333 if (status == UpdateChecker::UpdateFound) {
334 QSettings settings;
335 SettingTimer timer("mainwindow/last_remind_update_time");
336 const int seconds_per_day = 86400;
337 const unsigned int prev_update_version =
338 settings.value("mainwindow/last_remind_update_version").toUInt();
339 const unsigned int new_update_version = m_update_checker->versionId();
340 const bool timeout = !timer.isValid()
341 || timer.elapsedSeconds() > seconds_per_day;
342 const bool is_different_version =
343 new_update_version != prev_update_version;
344
345 // Show update dialog only if the update dialog has not been shown
346 // for a certain period or the version is different.
347 if (timeout || is_different_version) {
348 UpdateDialog(this).exec(*m_update_checker);
349 timer.restart();
350 settings.setValue("mainwindow/last_remind_update_version",
351 new_update_version);
352 }
353 }
354 }
355
356 // Private Methods
357
358 /* Check if all execute conditions are met.
359 This function should return true if all the conditions are met
360 and return false if any of the conditions fails.
361 */
check_execute_conditions()362 bool MainWindow::check_execute_conditions()
363 {
364 QString errmsg;
365
366 // check external programs
367 if (!MediaConverter::checkExternalPrograms(errmsg)) {
368 QMessageBox::critical(this, this->windowTitle(), errmsg);
369 #ifdef TOOLS_IN_DATA_PATH
370 return false; // fatal: ffmpeg should be in the data path but doesn't exist
371 #else
372 QTimer::singleShot(0, this, SLOT(slotSetTools()));
373 #endif
374 }
375 // load presets
376 if (!load_presets())
377 return false;
378
379 return true;
380 }
381
382 // We should respect the user and ask before connecting to the Internet to
383 // check for updates.
384 // If the user says yes, remember the decision and don't ask next time.
385 // If the user says no, disable checking for updates on startup.
ask_for_update_permission()386 bool MainWindow::ask_for_update_permission()
387 {
388 const char *setting_key = "update_permission";
389 QSettings settings;
390 bool permitted = settings.value(setting_key, false).toBool();
391 if (permitted) return true;
392
393 QString msg = tr("This program is going to check for updates online. "
394 "Do you allow this program to use the Internet "
395 "to check for updates?");
396
397 int reply = QMessageBox::information(this,
398 windowTitle(),
399 msg,
400 QMessageBox::Yes,
401 QMessageBox::No);
402
403 if (reply == QMessageBox::Yes) { // permitted
404 settings.setValue(setting_key, true); // don't ask next time
405 return true;
406 } else { // rejected
407 // disable auto update because the user probably doesn't like it
408 settings.setValue("options/check_update_on_startup", false);
409 return false;
410 }
411 }
412
413 // Popup wizard to add tasks.
add_files()414 void MainWindow::add_files()
415 {
416 AddTaskWizard wizard(m_presets, this);
417
418 if (wizard.exec_openfile() == QDialog::Accepted) {
419 // Add all input files to the list.
420 const QList<ConversionParameters> ¶mList = wizard.getConversionParameters();
421 m_list->addTasks(paramList);
422 }
423 }
424
add_files(const QStringList & fileList)425 void MainWindow::add_files(const QStringList &fileList)
426 {
427 AddTaskWizard wizard(m_presets, this);
428
429 if (wizard.exec(fileList) == QDialog::Accepted) {
430 // Add all input files to the list.
431 const QList<ConversionParameters> ¶mList = wizard.getConversionParameters();
432 m_list->addTasks(paramList);
433 }
434 }
435
setup_widgets()436 void MainWindow::setup_widgets()
437 {
438 // list
439 ui->layoutListPlaceholder->addWidget(m_list);
440 m_list->adjustSize();
441 m_list->setContextMenuPolicy(Qt::CustomContextMenu);
442
443 ui->lblTime->clear();
444 }
445
setup_menus()446 void MainWindow::setup_menus()
447 {
448 /* === Menu Events === */
449
450 // File
451 connect(ui->actionAddFiles, SIGNAL(triggered()),
452 this, SLOT(slotAddFiles()));
453 connect(ui->actionOptions, SIGNAL(triggered()),
454 this, SLOT(slotOptions()));
455 connect(ui->actionExit, SIGNAL(triggered()),
456 this, SLOT(slotExit()));
457
458 // Edit
459 connect(ui->menuEdit, SIGNAL(aboutToShow()),
460 this, SLOT(refresh_action_states()));
461 connect(ui->actionRemoveSelectedItems, SIGNAL(triggered()),
462 m_list, SLOT(removeSelectedItems()));
463 connect(ui->actionRemoveCompletedItems, SIGNAL(triggered()),
464 m_list, SLOT(removeCompletedItems()));
465 connect(ui->actionClearList, SIGNAL(triggered()),
466 m_list, SLOT(clear()));
467 connect(ui->actionSetParameters, SIGNAL(triggered()),
468 this, SLOT(slotSetConversionParameters()));
469 connect(ui->actionOpenOutputFolder, SIGNAL(triggered()),
470 this, SLOT(slotOpenOutputFolder()));
471 connect(ui->actionChangeOutputFilename, SIGNAL(triggered()),
472 m_list, SLOT(changeSelectedOutputFile()));
473 connect(ui->actionChangeOutputDirectory, SIGNAL(triggered()),
474 m_list, SLOT(changeSelectedOutputDirectory()));
475 connect(ui->actionShowErrorMessage, SIGNAL(triggered()),
476 m_list, SLOT(showErrorMessage()));
477 connect(ui->actionCut, SIGNAL(triggered()), SLOT(slotCut()));
478 ui->actionCut->setVisible(InteractiveCuttingDialog::available());
479
480 // Convert
481 connect(ui->menuConvert, SIGNAL(aboutToShow()),
482 this, SLOT(refresh_action_states()));
483 connect(ui->actionStartConversion, SIGNAL(triggered()),
484 this, SLOT(slotStartConversion()));
485 connect(ui->actionStopConversion, SIGNAL(triggered()),
486 this, SLOT(slotStopConversion()));
487 connect(ui->actionRetry, SIGNAL(triggered()),
488 m_list, SLOT(retrySelectedItems()));
489 connect(ui->actionRetry, SIGNAL(triggered()),
490 this, SLOT(refresh_action_states()));
491 connect(ui->actionRetryAll, SIGNAL(triggered()),
492 m_list, SLOT(retryAll()));
493 connect(ui->actionRetryAll, SIGNAL(triggered()),
494 this, SLOT(refresh_action_states()));
495
496 // About
497 connect(ui->actionAboutQt, SIGNAL(triggered()),
498 this, SLOT(slotAboutQt()));
499 connect(ui->actionAboutFFmpeg, SIGNAL(triggered()),
500 this, SLOT(slotAboutFFmpeg()));
501 connect(ui->actionAbout, SIGNAL(triggered()),
502 this, SLOT(slotAbout()));
503 connect(ui->actionCheckUpdate, SIGNAL(triggered()),
504 this, SLOT(slotShowUpdateDialog()));
505 }
506
setup_toolbar(const QStringList & entries)507 void MainWindow::setup_toolbar(const QStringList &entries)
508 {
509 Q_ASSERT(m_poweroff_button && "setup_poweroff_button() must be called first");
510
511 // construct a table of available actions
512 // map action name to action pointer
513 QMap<QString, QAction*> toolbar_table;
514 #define ADD_ACTION(name) toolbar_table[QString(#name).toUpper()] = ui->action ## name
515 ADD_ACTION(AddFiles);
516 ADD_ACTION(Options);
517 ADD_ACTION(Exit);
518 ADD_ACTION(RemoveSelectedItems);
519 ADD_ACTION(RemoveCompletedItems);
520 ADD_ACTION(ClearList);
521 ADD_ACTION(OpenOutputFolder);
522 ADD_ACTION(SetParameters);
523 ADD_ACTION(ChangeOutputFilename);
524 ADD_ACTION(ChangeOutputDirectory); // TODO: rename to "folder"
525 ADD_ACTION(ShowErrorMessage);
526 ADD_ACTION(StartConversion);
527 ADD_ACTION(StopConversion);
528 ADD_ACTION(Retry);
529 ADD_ACTION(RetryAll);
530 // "Shutdown" button is special, so we don't add it here
531 #define POWEROFF_BUTTON_NAME "POWEROFF"
532 ADD_ACTION(AboutQt);
533 ADD_ACTION(AboutFFmpeg);
534 ADD_ACTION(About);
535 ADD_ACTION(CheckUpdate);
536
537 for (int i=0; i<entries.size(); i++) {
538 QString entry = entries[i].toUpper(); // case-insensitive compare
539 if (entry == POWEROFF_BUTTON_NAME && PowerManagement::implemented())
540 ui->toolBar->addWidget(m_poweroff_button);
541 else if (entry == "|") // separator
542 ui->toolBar->addSeparator();
543 else if (toolbar_table.contains(entry))
544 ui->toolBar->addAction(toolbar_table[entry]);
545 }
546 }
547
setup_statusbar()548 void MainWindow::setup_statusbar()
549 {
550 ui->statusBar->addPermanentWidget(m_elapsedTimeLabel);
551 }
552
553 /*
554 * Setup the poweroff button and menu.
555 * The poweroff button is handled differently from other menu and buttons.
556 * Its icon and title changes as the action changes.
557 * When this function finishes, m_poweroff_button will point to the constructed
558 * button widget.
559 */
setup_poweroff_button()560 void MainWindow::setup_poweroff_button()
561 {
562 QToolButton *button = new QToolButton(this);
563 QMenu *menu = new QMenu(this);
564 QList<QAction*> actionList;
565 QSignalMapper *signalMapper = new QSignalMapper(this);
566 QActionGroup *checkGroup = new QActionGroup(this);
567
568 m_poweroff_button = button;
569 m_poweroff_actiongroup = checkGroup;
570
571 // Insert all actions into the list.
572 for (int i=0; i<PowerManagement::ACTION_COUNT; i++) {
573 const char *icon_id = "";
574 QString text = "";
575 switch (i) {
576 case PowerManagement::SHUTDOWN:
577 //: Shutdown the computer (completely poweroff)
578 text = tr("Shutdown");
579 icon_id = ":/actions/icons/system_shutdown.png";
580 break;
581 case PowerManagement::SUSPEND:
582 //: Suspend the computer (sleep to ram, standby)
583 text = tr("Suspend");
584 icon_id = ":/actions/icons/system_suspend.png";
585 break;
586 case PowerManagement::HIBERNATE:
587 //: Hibernate the computer (sleep to disk, completely poweroff)
588 text = tr("Hibernate");
589 icon_id = ":/actions/icons/system_hibernate.png";
590 break;
591 default:
592 Q_ASSERT(!"Incorrect id! Be sure to implement every power action in switch().");
593 }
594 actionList.append(new QAction(QIcon(icon_id)
595 , text, this));
596 }
597
598 // Add all actions into the menu (from list)
599 foreach (QAction *action, actionList) {
600 menu->addAction(action);
601 action->setCheckable(true);
602 action->setActionGroup(checkGroup);
603 }
604
605 button->setMenu(menu);
606 button->setPopupMode(QToolButton::MenuButtonPopup);
607
608 // ensure that the toolbutton and actionPoweroff are both checkable
609 ui->actionPoweroff->setCheckable(true);
610 button->setCheckable(true);
611 button->setChecked(false);
612
613 /* Synchronize the checked state of the toolbutton and actionPoweroff.
614 This cyclic connection doesn't cause an infinite loop because
615 toggled(bool) is only triggered when the checked() state changes.
616 */
617 connect(button, SIGNAL(toggled(bool))
618 , ui->actionPoweroff, SLOT(setChecked(bool)));
619 connect(ui->actionPoweroff, SIGNAL(toggled(bool))
620 , button, SLOT(setChecked(bool)));
621
622 // update the poweroff button when the action changes
623 for (int i=0; i<actionList.size(); i++) {
624 QAction *action = actionList.at(i);
625 signalMapper->setMapping(action, i);
626 connect(action, SIGNAL(triggered())
627 , signalMapper, SLOT(map()));
628 connect(signalMapper, SIGNAL(mapped(int))
629 , this, SLOT(update_poweroff_button(int)));
630 }
631
632 actionList.at(0)->trigger();
633
634 /* Check if the power management functions are available.
635 If not, hide poweroff button and menus.
636 */
637 if (!PowerManagement::implemented()) {
638 m_poweroff_button->setVisible(false);
639 ui->actionPoweroff->setVisible(false);
640 }
641 }
642
643 // Fill window icon with multiple sizes of images.
setup_appicon()644 void MainWindow::setup_appicon()
645 {
646 QIcon icon;
647 QDir iconDir = QDir(":/app/icons/");
648 QStringList fileList = iconDir.entryList();
649 QRegExp pattern("^qwinff_[0-9]+x[0-9]+\\.png$");
650 foreach (QString file, fileList) {
651 if (pattern.indexIn(file) >= 0) {
652 icon.addPixmap(QPixmap(iconDir.absoluteFilePath(file)));
653 }
654 }
655 setWindowIcon(icon);
656 ui->actionAbout->setIcon(icon);
657 }
658
set_poweroff_behavior(int action)659 void MainWindow::set_poweroff_behavior(int action)
660 {
661 if (action >= PowerManagement::ACTION_COUNT)
662 action = PowerManagement::SHUTDOWN;
663 m_poweroff_actiongroup->actions().at(action)->trigger();
664 }
665
get_poweroff_behavior()666 int MainWindow::get_poweroff_behavior()
667 {
668 for (int i=0; i<m_poweroff_actiongroup->actions().size(); i++) {
669 if (m_poweroff_actiongroup->actions().at(i)->isChecked())
670 return i;
671 }
672 return PowerManagement::SHUTDOWN;
673 }
674
load_presets()675 bool MainWindow::load_presets()
676 {
677 // The default preset file is located in <datapath>/presets.xml
678 //QString default_preset_file = QDir(Paths::dataPath()).absoluteFilePath("presets.xml");
679 QString app_path = QString(DATA_PATH);
680 QString default_preset_file = QDir(app_path).absoluteFilePath("presets.xml");
681
682 QString local_preset_file;
683 if (!Constants::getBool("Portable")) { // non-portable app
684 // rename local preset file created by older versions of qwinff
685 // operation: mv ~/.qwinff/presets.xml ~/.qwinff/presets.xml.old
686 QString local_preset_file_old = QDir(QDir::homePath()).absoluteFilePath(".qwinff/presets.xml");
687 if (QFile(local_preset_file_old).exists()) {
688 QFile::remove(local_preset_file_old + ".old");
689 if (QFile::rename(local_preset_file_old, local_preset_file_old + ".old")) {
690 qDebug() << local_preset_file_old + " is no longer used, "
691 "rename to " + local_preset_file_old + ".old";
692 }
693 }
694
695 // use global preset temporarily
696 local_preset_file = default_preset_file;
697 } else {
698 // portable app
699 local_preset_file = default_preset_file;
700 }
701
702 QSettings settings;
703 bool removeUnavailableCodecs = settings.value("options/hideformats", true).toBool();
704 // Load the preset file from the user's home directory
705 // The presets are loaded once and shared between objects
706 // that need the information.
707 if (!m_presets->readFromFile(local_preset_file, removeUnavailableCodecs)) {
708 QMessageBox::critical(this, this->windowTitle(),
709 tr("Failed to load preset file. "
710 "The application will quit now."));
711 return false;
712 }
713 return true;
714 }
715
716 // Hide unused actions
refresh_action_states()717 void MainWindow::refresh_action_states()
718 {
719 int selected_file_count = m_list->selectedCount();
720
721 // Hide actionSetParameters if no item in m_list is selected.
722 bool hide_SetParameters = (selected_file_count == 0);
723
724 // Hide actionStartConversion if the conversion is in progress.
725 bool hide_StartConversion = m_list->isBusy();
726
727 // Hide actionStopConversion if nothing is being converted.
728 bool hide_StopConversion = !m_list->isBusy();
729
730 // Show actionOpenOutputFolder only if 1 file is selected.
731 bool hide_OpenFolder = (selected_file_count <= 0);
732
733 // Hide actionRemoveSelectedItems if no file is selected.
734 bool hide_RemoveSelectedItems = (selected_file_count == 0);
735
736 bool hide_Retry = (selected_file_count == 0);
737 bool hide_RetryAll = (m_list->isEmpty());
738
739 bool hide_ClearList = (m_list->isEmpty());
740
741 bool hide_ChangeOutputFilename = m_list->selectedCount() != 1;
742 bool hide_ChangeOutputDirectory = m_list->selectedCount() <= 0;
743
744
745 /* Show actionShowErrorMessage if and only if one task is selected
746 and the state of the selected task is FAILED
747 */
748 bool hide_ShowErrorMessage = (selected_file_count != 1
749 || !m_list->selectedTaskFailed());
750
751 ui->actionSetParameters->setDisabled(hide_SetParameters);
752 ui->actionStartConversion->setDisabled(hide_StartConversion);
753 ui->actionStopConversion->setDisabled(hide_StopConversion);
754 ui->actionOpenOutputFolder->setDisabled(hide_OpenFolder);
755 ui->actionRemoveSelectedItems->setDisabled(hide_RemoveSelectedItems);
756 ui->actionRetry->setDisabled(hide_Retry);
757 ui->actionRetryAll->setDisabled(hide_RetryAll);
758 ui->actionClearList->setDisabled(hide_ClearList);
759 ui->actionChangeOutputFilename->setDisabled(hide_ChangeOutputFilename);
760 ui->actionChangeOutputDirectory->setDisabled(hide_ChangeOutputDirectory);
761 ui->actionShowErrorMessage->setDisabled(hide_ShowErrorMessage);
762 ui->actionCut->setEnabled(selected_file_count == 1); // cut only 1 file at a time
763 }
764
load_settings()765 void MainWindow::load_settings()
766 {
767 QSettings settings;
768 restoreGeometry(settings.value("mainwindow/geometry").toByteArray());
769 restoreState(settings.value("mainwindow/state").toByteArray());
770 int poweroff_behavior = settings.value("options/poweroff_behavior"
771 , PowerManagement::SHUTDOWN).toInt();
772 set_poweroff_behavior(poweroff_behavior);
773
774 }
775
save_settings()776 void MainWindow::save_settings()
777 {
778 QSettings settings;
779 settings.setValue("mainwindow/geometry", saveGeometry());
780 settings.setValue("mainwindow/state", saveState());
781 settings.setValue("options/poweroff_behavior", get_poweroff_behavior());
782 }
783
refresh_status()784 void MainWindow::refresh_status()
785 {
786 refresh_statusbar();
787 refresh_titlebar();
788 }
789
refresh_statusbar()790 void MainWindow::refresh_statusbar()
791 {
792 if (m_list->isBusy()) {
793 int total_seconds = m_list->elapsedTime() / 1000;
794 int hours = total_seconds / 3600;
795 int minutes = (total_seconds / 60) % 60;
796 int seconds = total_seconds % 60;
797
798 QString timeinfo = tr("Elapsed Time: %1 h %2 m %3 s")
799 .arg(hours).arg(minutes).arg(seconds);
800 //m_elapsedTimeLabel->setText(timeinfo);
801 ui->lblTime->setText(timeinfo);
802 } else {
803 //m_elapsedTimeLabel->clear();
804 //ui->lblTime->clear();
805 }
806 }
807
refresh_titlebar()808 void MainWindow::refresh_titlebar()
809 {
810 const int task_count = m_list->count();
811 const int finished_task_count = m_list->finishedCount();
812 if (finished_task_count < task_count && m_list->isBusy()) {
813 //: Converting the %1-th file in %2 files. %2 is the number of files.
814 setWindowTitle(tr("Converting %1/%2")
815 .arg(finished_task_count+1).arg(task_count));
816 } else {
817 setWindowTitle(tr("QWinFF"));
818 }
819 }
820