#include #include #include #include #include #include #include #include #include #include "MainWindow.h" #include "Sheet.h" #include "VisualizationWiew.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { this->setWindowTitle(tr("Heat Transmission Simulation v1.0")); this->buildInterface(); this->resize(800, 600); this->setAcceptDrops(true); } void MainWindow::buildInterface() { // Central widget: simulation area this->visualizationWiew = new VisualizationWiew(this); this->setCentralWidget(this->visualizationWiew); this->connect(this->visualizationWiew, &VisualizationWiew::refreshed, this, &MainWindow::refreshProgress); // Simulation params QWidget* simulationParams = new QWidget(this); QHBoxLayout* layout = new QHBoxLayout(); simulationParams->setLayout(layout); // Epsilon layout->addWidget( new QLabel(tr("Epsilon")) ); this->epsilonControl = new QLineEdit("0.001"); layout->addWidget( this->epsilonControl ); // Refresh rate layout->addWidget( new QLabel(tr("Refresh rate (ms)")) ); this->refreshRateControl = new QLineEdit("200"); this->connect( this->refreshRateControl, &QLineEdit::textChanged, this->visualizationWiew, &VisualizationWiew::setRefreshRateText ); layout->addWidget( this->refreshRateControl ); // Start/pause simulation button this->startPauseButton = new QPushButton(tr("&Start")); this->startPauseButton->setEnabled(false); this->connect( this->startPauseButton, &QPushButton::clicked, this, &MainWindow::startPauseSimulation ); layout->addWidget( this->startPauseButton ); // Stop simultation button this->stopButton = new QPushButton(tr("S&top")); this->stopButton->setEnabled(false); this->connect( this->stopButton, &QPushButton::clicked, this, &MainWindow::stopSimulation ); layout->addWidget( this->stopButton ); // Simulation param dock widget QDockWidget* dock = new QDockWidget(tr("Simulation params"), this); dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); dock->setWidget(simulationParams); this->addDockWidget(Qt::BottomDockWidgetArea, dock); this->statusBar()->showMessage(tr("Drag and drop a CSV file to load a sheet")); } void MainWindow::dragEnterEvent(QDragEnterEvent* event) { // Only accept to drag files when it is not simulating if ( event->mimeData()->hasUrls() && this->state != State::simulating ) event->acceptProposedAction(); } void MainWindow::dropEvent(QDropEvent* event) { // Something was dropped into the main window const QMimeData* mimeData = event->mimeData(); // Check for our needed mime type, here a file or a list of files if ( mimeData->hasUrls() ) { // Get the list of droped files as URLs QList urlList = mimeData->urls(); // If only one file was given if ( urlList.count() == 1 ) { // Load the temperatures matrix const QString& filePath = urlList[0].toLocalFile(); this->statusBar()->showMessage( tr("Opening %1...").arg(filePath) ); this->loadCsv( filePath ); } else { this->statusBar()->showMessage( tr("Drop just one file") ); } } } bool MainWindow::loadCsv(const QString& filePath) { // Create a data source and load it from the file Sheet* sheet = Sheet::load(filePath, this); if ( sheet ) { // Report the file was successfully loaded QFileInfo fileInfo(filePath); this->statusBar()->showMessage( tr("%1 loaded with %2 rows and %3 columns from temperature %4 to %5") .arg(fileInfo.fileName()).arg(sheet->getRows()).arg(sheet->getColumns()) .arg(sheet->getMinimum()).arg(sheet->getMaximum()) ); // Enable controls to start the simulation this->visualizationWiew->setSheet(sheet); this->startPauseButton->setEnabled(true); // Enable controls again when the simulation finishes automatically // because the changes do not surpass the epsilon this->connect( sheet, &Sheet::simulationDone, this, &MainWindow::simulationDone ); return true; } else { // The csv was not valid, report an error this->statusBar()->showMessage( tr("Error loading %1").arg(filePath) ); return false; } } void MainWindow::startPauseSimulation() { // Depends on the state of the simulation if ( this->state == State::stopped || this->state == State::paused ) { // Start or resume simulation this->startResumeSimulation(); } else if ( this->state == State::simulating ) { // Pause simulation this->pauseSimulation(); } else { // The Start/Pause button must be disabled Q_ASSERT(false); } } void MainWindow::startResumeSimulation() { // Get the epsilon from interface and block the control bool ok = true; double epsilon = this->epsilonControl->text().toDouble(&ok); // Check if given epsilon is valid if ( ok && epsilon >= 0.0 ) { // Start or resume simulation this->state = State::simulating; this->time.start(); this->startPauseButton->setText( tr("&Pause") ); this->epsilonControl->setEnabled(false); this->stopButton->setEnabled(true); this->visualizationWiew->start(epsilon); } else { this->statusBar()->showMessage( tr("Invalid epsilon %1").arg(this->epsilonControl->text()) ); } } void MainWindow::pauseSimulation() { this->state = State::paused; this->startPauseButton->setText( tr("&Resume") ); this->visualizationWiew->stop(); this->epsilonControl->setEnabled(true); } void MainWindow::stopSimulation() { this->state = State::stopped; this->startPauseButton->setText( tr("&Start") ); this->visualizationWiew->stop(); this->stopButton->setEnabled(false); this->epsilonControl->setEnabled(true); } void MainWindow::simulationDone(unsigned long long generations) { const double duration = this->time.elapsed() / 1000.0; this->stopSimulation(); this->statusBar()->showMessage( tr("Simulation finished in %1 seconds at generation %2") .arg(duration).arg(generations) ); } #include void MainWindow::refreshProgress() { // Calculate the elapsed time in human-readable form const long duration = this->time.elapsed() / 1000; const long ss = duration % 60; const long mm = duration / 60 % 60; const long hh = duration / 60 / 60; // Show the time and current generation showed by the visualization unsigned long long generation = this->visualizationWiew->getSheet()->getGeneration(); this->statusBar()->showMessage( tr("%1:%2:%3s Generation %4") .arg(hh).arg(mm, 2, 10, QChar('0')).arg(ss, 2, 10, QChar('0')).arg(generation) ); }