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
27const QString MainWindow::Setting_OpenLocation = QLatin1String("OpenFilesLocation");
28const QString MainWindow::Setting_OutputLocation = QLatin1String("OutputLocation");
29const QString MainWindow::Setting_WindowState = QLatin1String("WindowState");
30const QString MainWindow::Setting_WindowGeometry = QLatin1String("WindowGeometry");
31
32using namespace ThreadWeaver;
33
34MainWindow::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
95MainWindow::~MainWindow()
96{
97 delete ui;
98}
99
100void MainWindow::closeEvent(QCloseEvent *event)
101{
102 event->ignore();
103 QMainWindow::closeEvent(event);
104 slotQuit();
105}
106
107void 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
115void 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
133void 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
146void 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
153void 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
160void 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
167void 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
174void 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
181void MainWindow::slotEnableAverageLoadManager(bool enabled)
182{
183 m_averageLoadManager->activate(enabled);
184}
185
186void 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
197void 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

source code of threadweaver/examples/ThumbNailer/MainWindow.cpp