| 1 | /* -*- C++ -*- |
| 2 | This file is part of ThreadWeaver. |
| 3 | |
| 4 | SPDX-FileCopyrightText: 2005-2014 Mirko Boehm <mirko@kde.org> |
| 5 | |
| 6 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 7 | */ |
| 8 | |
| 9 | #include <QApplication> |
| 10 | #include <QCheckBox> |
| 11 | #include <QCloseEvent> |
| 12 | #include <QFileDialog> |
| 13 | #include <QSettings> |
| 14 | #include <QSortFilterProxyModel> |
| 15 | #include <QString> |
| 16 | #include <QVariant> |
| 17 | |
| 18 | #include <ThreadWeaver/ThreadWeaver> |
| 19 | |
| 20 | #include "AverageLoadManager.h" |
| 21 | #include "ImageListFilter.h" |
| 22 | #include "ItemDelegate.h" |
| 23 | #include "MainWindow.h" |
| 24 | |
| 25 | #include "ui_MainWindow.h" |
| 26 | |
| 27 | const QString MainWindow::Setting_OpenLocation = QLatin1String("OpenFilesLocation" ); |
| 28 | const QString MainWindow::Setting_OutputLocation = QLatin1String("OutputLocation" ); |
| 29 | const QString MainWindow::Setting_WindowState = QLatin1String("WindowState" ); |
| 30 | const QString MainWindow::Setting_WindowGeometry = QLatin1String("WindowGeometry" ); |
| 31 | |
| 32 | using namespace ThreadWeaver; |
| 33 | |
| 34 | MainWindow::MainWindow(QWidget *parent) |
| 35 | : QMainWindow(parent) |
| 36 | , ui(new Ui::MainWindow) |
| 37 | , m_fileLoaderFilter(new ImageListFilter(Image::Step_LoadFile, this)) |
| 38 | , m_imageLoaderFilter(new ImageListFilter(Image::Step_LoadImage, this)) |
| 39 | , m_imageScalerFilter(new ImageListFilter(Image::Step_ComputeThumbNail, this)) |
| 40 | , m_imageWriterFilter(new ImageListFilter(Image::Step_SaveThumbNail, this)) |
| 41 | , m_averageLoadManager(new AverageLoadManager(this)) |
| 42 | { |
| 43 | ui->setupUi(this); |
| 44 | // The file loader list: |
| 45 | m_fileLoaderFilter->setSourceModel(&m_model); |
| 46 | ui->fileLoaderList->setModel(m_fileLoaderFilter); |
| 47 | ui->fileLoaderList->setItemDelegate(new ItemDelegate(this)); |
| 48 | ui->fileLoaderCap->setValue(m_model.fileLoaderCap()); |
| 49 | // The image loader list: |
| 50 | m_imageLoaderFilter->setSourceModel(&m_model); |
| 51 | ui->imageLoaderList->setModel(m_imageLoaderFilter); |
| 52 | ui->imageLoaderList->setItemDelegate(new ItemDelegate(this)); |
| 53 | ui->imageLoaderCap->setValue(m_model.imageLoaderCap()); |
| 54 | |
| 55 | // The image scaler list: |
| 56 | m_imageScalerFilter->setSourceModel(&m_model); |
| 57 | ui->imageScalerList->setModel(m_imageScalerFilter); |
| 58 | ui->imageScalerList->setItemDelegate(new ItemDelegate(this)); |
| 59 | ui->imageScalerCap->setValue(m_model.computeThumbNailCap()); |
| 60 | |
| 61 | // The image writer list: |
| 62 | m_imageWriterFilter->setSourceModel(&m_model); |
| 63 | ui->imageWriterList->setModel(m_imageWriterFilter); |
| 64 | ui->imageWriterList->setItemDelegate(new ItemDelegate(this)); |
| 65 | ui->fileWriterCap->setValue(m_model.saveThumbNailCap()); |
| 66 | |
| 67 | ui->workers->setValue(Queue::instance()->maximumNumberOfThreads()); |
| 68 | |
| 69 | // Configure average load manager: |
| 70 | ui->loadManager->setEnabled(m_averageLoadManager->available()); |
| 71 | connect(asender: ui->loadManager, SIGNAL(toggled(bool)), SLOT(slotEnableAverageLoadManager(bool))); |
| 72 | |
| 73 | connect(asender: ui->actionOpen_Files, SIGNAL(triggered()), SLOT(slotOpenFiles())); |
| 74 | connect(asender: ui->outputDirectory, SIGNAL(clicked()), SLOT(slotSelectOutputDirectory())); |
| 75 | connect(asender: ui->actionQuit, SIGNAL(triggered()), SLOT(slotQuit())); |
| 76 | connect(asender: &m_model, SIGNAL(progress(int, int)), SLOT(slotProgress(int, int))); |
| 77 | connect(asender: ui->fileLoaderCap, SIGNAL(valueChanged(int)), SLOT(slotFileLoaderCapChanged())); |
| 78 | connect(asender: ui->imageLoaderCap, SIGNAL(valueChanged(int)), SLOT(slotImageLoaderCapChanged())); |
| 79 | connect(asender: ui->imageScalerCap, SIGNAL(valueChanged(int)), SLOT(slotComputeThumbNailCapChanged())); |
| 80 | connect(asender: ui->fileWriterCap, SIGNAL(valueChanged(int)), SLOT(slotSaveThumbNailCapChanged())); |
| 81 | |
| 82 | connect(asender: ui->workers, SIGNAL(valueChanged(int)), SLOT(slotWorkerCapChanged())); |
| 83 | |
| 84 | QSettings settings; |
| 85 | m_outputDirectory = settings.value(key: Setting_OutputLocation).toString(); |
| 86 | if (!m_outputDirectory.isEmpty()) { |
| 87 | ui->outputDirectory->setText(m_outputDirectory); |
| 88 | } |
| 89 | restoreGeometry(geometry: settings.value(key: Setting_WindowGeometry).toByteArray()); |
| 90 | restoreState(state: settings.value(key: Setting_WindowState).toByteArray()); |
| 91 | |
| 92 | connect(asender: m_averageLoadManager, SIGNAL(recommendedWorkerCount(int)), SLOT(slotRecommendedWorkerCountChanged(int))); |
| 93 | } |
| 94 | |
| 95 | MainWindow::~MainWindow() |
| 96 | { |
| 97 | delete ui; |
| 98 | } |
| 99 | |
| 100 | void MainWindow::closeEvent(QCloseEvent *event) |
| 101 | { |
| 102 | event->ignore(); |
| 103 | QMainWindow::closeEvent(event); |
| 104 | slotQuit(); |
| 105 | } |
| 106 | |
| 107 | void MainWindow::slotProgress(int step, int total) |
| 108 | { |
| 109 | ui->progressBar->setMinimum(0); |
| 110 | ui->progressBar->setMaximum(total); |
| 111 | ui->progressBar->setValue(step); |
| 112 | ui->actionOpen_Files->setEnabled(step >= total); |
| 113 | } |
| 114 | |
| 115 | void MainWindow::slotOpenFiles() |
| 116 | { |
| 117 | QSettings settings; |
| 118 | const QString previousLocation = settings.value(key: Setting_OpenLocation, defaultValue: QDir::homePath()).toString(); |
| 119 | auto const files = QFileDialog::getOpenFileNames(parent: this, caption: tr(s: "Select images to convert" ), dir: previousLocation); |
| 120 | if (files.isEmpty()) { |
| 121 | return; |
| 122 | } |
| 123 | if (m_outputDirectory.isNull()) { |
| 124 | slotSelectOutputDirectory(); |
| 125 | } |
| 126 | m_model.clear(); |
| 127 | const QFileInfo fi(files.at(i: 0)); |
| 128 | settings.setValue(key: Setting_OpenLocation, value: fi.absolutePath()); |
| 129 | slotProgress(step: 0, total: files.count()); |
| 130 | m_model.queueUpConversion(files, outputDirectory: m_outputDirectory); |
| 131 | } |
| 132 | |
| 133 | void MainWindow::slotSelectOutputDirectory() |
| 134 | { |
| 135 | QSettings settings; |
| 136 | const QString previousLocation = settings.value(key: Setting_OutputLocation, defaultValue: QDir::homePath()).toString(); |
| 137 | auto directory = QFileDialog::getExistingDirectory(parent: this, caption: tr(s: "Select output directory..." )); |
| 138 | if (directory.isNull()) { |
| 139 | return; |
| 140 | } |
| 141 | m_outputDirectory = directory; |
| 142 | settings.setValue(key: Setting_OutputLocation, value: directory); |
| 143 | ui->outputDirectory->setText(directory); |
| 144 | } |
| 145 | |
| 146 | void MainWindow::slotFileLoaderCapChanged() |
| 147 | { |
| 148 | const int value = ui->fileLoaderCap->value(); |
| 149 | Q_ASSERT(value > 0); // limits set in UI file |
| 150 | m_model.setFileLoaderCap(value); |
| 151 | } |
| 152 | |
| 153 | void MainWindow::slotImageLoaderCapChanged() |
| 154 | { |
| 155 | const int value = ui->imageLoaderCap->value(); |
| 156 | Q_ASSERT(value > 0); // limits set in UI file |
| 157 | m_model.setImageLoaderCap(value); |
| 158 | } |
| 159 | |
| 160 | void MainWindow::slotComputeThumbNailCapChanged() |
| 161 | { |
| 162 | const int value = ui->imageScalerCap->value(); |
| 163 | Q_ASSERT(value > 0); // limits set in UI file |
| 164 | m_model.setComputeThumbNailCap(value); |
| 165 | } |
| 166 | |
| 167 | void MainWindow::slotSaveThumbNailCapChanged() |
| 168 | { |
| 169 | const int value = ui->fileWriterCap->value(); |
| 170 | Q_ASSERT(value > 0); // limits set in UI file |
| 171 | m_model.setSaveThumbNailCap(value); |
| 172 | } |
| 173 | |
| 174 | void MainWindow::slotWorkerCapChanged() |
| 175 | { |
| 176 | const int value = ui->workers->value(); |
| 177 | Q_ASSERT(value >= 0); // limits set in UI file |
| 178 | Queue::instance()->setMaximumNumberOfThreads(value); |
| 179 | } |
| 180 | |
| 181 | void MainWindow::slotEnableAverageLoadManager(bool enabled) |
| 182 | { |
| 183 | m_averageLoadManager->activate(enabled); |
| 184 | } |
| 185 | |
| 186 | void MainWindow::slotRecommendedWorkerCountChanged(int value) |
| 187 | { |
| 188 | auto const minMax = m_averageLoadManager->workersRange(); |
| 189 | ui->workersSlider->setRange(min: minMax.first, max: minMax.second); |
| 190 | ui->workersSlider->setValue(value); |
| 191 | ui->loadManager->setText(tr(s: "%1 workers" ).arg(a: value)); |
| 192 | ui->workersMin->setText(QString::number(minMax.first)); |
| 193 | ui->workersMax->setText(QString::number(minMax.second)); |
| 194 | Queue::instance()->setMaximumNumberOfThreads(value); |
| 195 | } |
| 196 | |
| 197 | void MainWindow::slotQuit() |
| 198 | { |
| 199 | QSettings settings; |
| 200 | settings.setValue(key: Setting_WindowGeometry, value: saveGeometry()); |
| 201 | settings.setValue(key: Setting_WindowState, value: saveState()); |
| 202 | ThreadWeaver::Queue::instance()->dequeue(); |
| 203 | ThreadWeaver::Queue::instance()->finish(); |
| 204 | QApplication::instance()->quit(); |
| 205 | } |
| 206 | |
| 207 | #include "moc_MainWindow.cpp" |
| 208 | |