Skip to content

File progress_box.cpp

File List > gui > progress_box.cpp

Go to the documentation of this file

#include "progress_box.hpp"

#include <QException>
#include <QFutureWatcher>
#include <QMessageBox>
#include <QtConcurrent>

#include "ui_progress_box.h"
#include "utilities/progress_tracker.hpp"

void ProgressBox::abort() { done(1); }

ProgressBox::ProgressBox(QWidget* parent) : QDialog(parent), ui(new Ui::ProgressBox) {
  ui->setupUi(this);
  setWindowFlag(Qt::WindowCloseButtonHint, false);
  connect(this, &ProgressBox::send_progress_bars, this, &ProgressBox::receive_progress_bars);
  connect(this, &ProgressBox::send_status_text, this, &ProgressBox::receive_status_text);
}

void ProgressBox::receive_progress_bars(std::vector<double> progress) {
  for (size_t i = 0; i < progress.size(); i++) {
    if (i >= m_progress.size()) {
      m_progress.emplace_back(
          std::pair<QProgressBar*, QLabel*>{new QProgressBar(ui->scrollAreaWidgetContents_2),
                                            new QLabel(ui->scrollAreaWidgetContents_2)});
      ui->verticalLayout_3->addWidget(m_progress.back().first);
      m_progress.back().first->setMaximum(1000);
      m_progress.back().second->setWordWrap(true);
      ui->verticalLayout_3->addWidget(m_progress.back().second);
    }
    m_progress[i].first->setValue(progress[i] * 1000);
  }
  for (size_t i = progress.size(); i < m_progress.size(); i++) {
    ui->verticalLayout_3->removeWidget(m_progress[i].first);
    delete m_progress[i].first;
    delete m_progress[i].second;
  }
  m_progress.resize(progress.size());
}

void ProgressBox::receive_status_text(std::string text, int depth) {
  if ((unsigned int)(depth - 1) < m_progress.size()) {
    m_progress[depth - 1].second->setText(QString::fromStdString(text));
  }
}

void ProgressBox::update_progress(double _) {
  (void)_;
  std::vector<double> progress;
  ProgressTracker* child = this->child();
  while (child != nullptr) {
    progress.push_back(child->proportion());
    child = child->child();
  }
  emit send_progress_bars(std::move(progress));
}

void ProgressBox::text_update(const std::string& text, int depth) {
  emit send_status_text(text, depth);
}

class TaskException : public QException {
  std::string m_what;

 public:
  TaskException(const char* what) : QException(), m_what(what) {}
  void raise() const { throw *this; }
  QException* clone() const { return new TaskException(*this); }
  inline virtual const char* what() const noexcept { return m_what.c_str(); }
};

void ProgressBox::start_task(std::function<void()> task, std::function<void()> on_finish) {
  QFutureWatcher<int>* watcher = new QFutureWatcher<int>(this);
  connect(watcher, &QFutureWatcher<int>::finished, this, [this, watcher, on_finish] {
    if (watcher->future().isCanceled()) {
      try {
        watcher->future().result();
      } catch (TaskException& e) {
        QMessageBox::critical(this, "Error running task", e.what());
      }
      this->done(1);
    } else {
      this->done(0);
      on_finish();
    }
  });
  watcher->setFuture(QtConcurrent::run([task] {
    try {
      task();
    } catch (std::exception& e) {
      throw TaskException(e.what());
    }
    return 0;
  }));
}