MainWindow.cpp 39.33 KiB
#include "MainWindow.h"
#include "TMath.h"
#include "TString.h"
//#include <iostream>
//#include "TList.h"
#include "TStyle.h"
#include "TFile.h"
#include "TTree.h"
#include "TGraph.h"
#include "TAxis.h"
#include "qrootcanvas.h"
#include <QVBoxLayout>
#include <TSystem.h>
#include <QTimer>
#include <QDebug>
#include <QWindow>
#include <QFileDialog>
#include <QDateTime>
#include <QMessageBox>
#include <QDoubleValidator>
#include <QIntValidator>
#include <QRegExpValidator>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// General
connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::handleOpenProj);
connect(ui->actionExit, &QAction::triggered, this, &MainWindow::handleClose);
connect(ui->actionSave, &QAction::triggered, this, &MainWindow::handleSave);
connect(ui->actionSave_As, &QAction::triggered, this, &MainWindow::handleSaveAs);
connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::handleAbout);
connect(ui->actionOpenPlot, &QAction::triggered, this, &MainWindow::handleOpenplot);
connect(ui->actionStart, &QAction::triggered, this, &MainWindow::handleStart);
connect(ui->actionPause, &QAction::triggered, this, &MainWindow::handlePause);
connect(ui->actionStop, &QAction::triggered, this, &MainWindow::handleStop);
// accepts user input and update config
// quit worker thread and clear plot data immediately when any settings are changed
connect(ui->openProject, &QPushButton::clicked, this, &MainWindow::handleOpenProj);
connect(ui->openFileButton, &QPushButton::clicked, this, &MainWindow::onOpenFileClicked);
ui->runIDInput->setValidator(new QRegExpValidator( QRegExp("[A-Za-z0-9_]+"), ui->runIDInput));
connect(ui->runIDInput, &QLineEdit::editingFinished, this, &MainWindow::onRunIDInput);
ui->maxEventNumInput->setValidator(new QIntValidator(1, 10000000,ui->maxEventNumInput));
connect(ui->maxEventNumInput, &QLineEdit::editingFinished, this, &MainWindow::onMaxEventNumInput);
// Plot
QDoubleValidator* rdv = new QDoubleValidator(1, 10000, 6, ui->radiusInput);
rdv->setNotation(QDoubleValidator::StandardNotation);
ui->radiusInput->setValidator(rdv);
connect(ui->radiusInput, &QLineEdit::editingFinished, this, &MainWindow::onRadiusInput);
ui->phiBinsInput->setValidator(new QIntValidator(1, 720, ui->phiBinsInput));
QDoubleValidator* phimindv = new QDoubleValidator(-180, 180, 6, ui->phiMinInput);
phimindv->setNotation(QDoubleValidator::StandardNotation);
ui->phiMinInput->setValidator(phimindv);
ui->phiMaxInput->setValidator(phimindv);
connect(ui->phiBinsInput, &QLineEdit::editingFinished, this, &MainWindow::onPhiBinsInput);
connect(ui->phiMinInput, &QLineEdit::editingFinished, this, &MainWindow::onPhiMinInput);
connect(ui->phiMaxInput, &QLineEdit::editingFinished, this, &MainWindow::onPhiMaxInput);
ui->thetaBinsInput->setValidator(new QIntValidator(1, 360, ui->thetaBinsInput));
QDoubleValidator* thetamindv = new QDoubleValidator(-90, 90, 6, ui->thetaMinInput);
thetamindv->setNotation(QDoubleValidator::StandardNotation);
ui->thetaMinInput->setValidator(thetamindv);
ui->thetaMaxInput->setValidator(thetamindv);
connect(ui->thetaBinsInput, &QLineEdit::editingFinished, this, &MainWindow::onThetaBinsInput);
connect(ui->thetaMinInput, &QLineEdit::editingFinished, this, &MainWindow::onThetaMinInput);
connect(ui->thetaMaxInput, &QLineEdit::editingFinished, this, &MainWindow::onThetaMaxInput);
ui->ergBinsInput->setValidator(new QIntValidator(1, 10000, ui->ergBinsInput));
QDoubleValidator* ergmindv = new QDoubleValidator(0, 50, 6, ui->ergMinInput);
ergmindv->setNotation(QDoubleValidator::StandardNotation);
ui->ergMinInput->setValidator(ergmindv);
ui->ergMaxInput->setValidator(ergmindv);
connect(ui->ergBinsInput, &QLineEdit::editingFinished, this, &MainWindow::onErgBinsInput);
connect(ui->ergMinInput, &QLineEdit::editingFinished, this, &MainWindow::onErgMinInput);
connect(ui->ergMaxInput, &QLineEdit::editingFinished, this, &MainWindow::onErgMaxInput);
QDoubleValidator* ergcutdv = new QDoubleValidator(0, 50, 6, ui->ergCutLowInput);
ergcutdv->setNotation(QDoubleValidator::StandardNotation);
ui->ergCutLowInput->setValidator(ergcutdv);
ui->ergCutHighInput->setValidator(ergcutdv);
connect(ui->enableErgCutBox, &QCheckBox::stateChanged, this, &MainWindow::onErgCutStateChanged);
connect(ui->ergCutLowInput, &QLineEdit::editingFinished, this, &MainWindow::onErgCutLowInput);
connect(ui->ergCutHighInput, &QLineEdit::editingFinished, this, &MainWindow::onErgCutHighInput);
connect(ui->saveImageBox, &QCheckBox::stateChanged, this, &MainWindow::onSaveImageStateChanged);
connect(ui->saveSpectrumBox, &QCheckBox::stateChanged, this, &MainWindow::onSaveSpectrumStateChanged);
connect(ui->saveImageFormat, &QComboBox::currentTextChanged, this, &MainWindow::onsaveImageFormatChanged);
connect(ui->saveSpectrumFormat, &QComboBox::currentTextChanged, this, &MainWindow::onsaveSpectrumFormatChanged);
QDoubleValidator* tmedv = new QDoubleValidator(0, 1000, 6, ui->timeWindowInput);
tmedv->setNotation(QDoubleValidator::StandardNotation);
ui->timeWindowInput->setValidator(tmedv);
connect(ui->timeWindowInput, &QLineEdit::editingFinished, this, &MainWindow::onTimeWindowInput);
// Mapping
collectWidgets();
QIntValidator* chNumv = new QIntValidator(0, 1024, chNumInputs[0]);
for (int i=0; i<chNumInputs.size(); i++) {
chNumInputs[i]->setValidator(chNumv);
connect(chNumInputs[i], &QLineEdit::editingFinished, this, &MainWindow::onChNumInput);
}
QDoubleValidator* posxdv = new QDoubleValidator(-10000, 10000, 6, posXInputs[0]);
posxdv->setNotation(QDoubleValidator::StandardNotation);
for (int i=0; i<posXInputs.size(); i++) {
posXInputs[i]->setValidator(posxdv);
connect(posXInputs[i], &QLineEdit::editingFinished, this, &MainWindow::onPosXInput);
}
QDoubleValidator* posydv = new QDoubleValidator(-10000, 10000, 6, posYInputs[0]);
posydv->setNotation(QDoubleValidator::StandardNotation);
for (int i=0; i<posYInputs.size(); i++) {
posYInputs[i]->setValidator(posydv);
connect(posYInputs[i], &QLineEdit::editingFinished, this, &MainWindow::onPosYInput);
}
QDoubleValidator* calidv = new QDoubleValidator(0, 10000, 6, caliCoefInputs[0]);
calidv->setNotation(QDoubleValidator::StandardNotation);
for (int i=0; i<caliCoefInputs.size(); i++) {
caliCoefInputs[i]->setValidator(calidv);
connect(caliCoefInputs[i], &QLineEdit::editingFinished, this, &MainWindow::onCaliCoefInput);
}
for (int i=0; i<chOnBoxes.size(); i++) {
connect(chOnBoxes[i], &QCheckBox::stateChanged, this, &MainWindow::onChOnStateChanged);
}
// user applies the config
// create a new worker thread, pop up a plot window
// connect(ui->applySettingsButton, &QPushButton::clicked, this, &MainWindow::onConfigApplied);
setWindowTitle(tr("Back projection"));
qDebug() << "Attempting to open a project";
if(!handleOpenProj())
{
qDebug() << "Cannot open project. Exit application.";
// QCoreApplication::exit(1);
exit(EXIT_FAILURE);
}
ui->statusBar->showMessage("Ready.");
}
void MainWindow::closeEvent (QCloseEvent *event)
{
QMessageBox::StandardButton resBtn = QMessageBox::question(this, "Close",
tr("Are you sure you want to quit?\n"),
QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
QMessageBox::Yes);
if (resBtn != QMessageBox::Yes) {
event->ignore();
} else {
if (workerThread) {
// qDebug() << "Exiting thread..";
// stop worker thread
// emit threadStopped();
ui->actionStop->trigger();
gSystem->Sleep(500);
}
event->accept();
}
}
MainWindow::~MainWindow()
{
delete ui;
if (config){
qDebug() << "write settings on main window closed";
config->writeSetup(config->outputDir.absolutePath() + "/settings.ini");
delete config;
qDebug() << "settings saved";
}
if (plotdata)
{
delete plotdata;
}
}
void MainWindow::handleOpenplot()
{
if(!plotwindow.isNull() && plotwindow->isVisible())
{
// bring to front
plotwindow->raise();
return;
}
qDebug() << "Open new plot window";
if(!plotdata)
{
QMessageBox::critical(this, "Warning", "Apply the settings first by pressing start button.");
return;
}
plotwindow = new QPlotWindow(this, config, plotdata);
connect(plotwindow, &QPlotWindow::runStarted, ui->actionStart, &QAction::trigger);
connect(plotwindow, &QPlotWindow::runPaused, ui->actionPause, &QAction::trigger);
connect(plotwindow,&QPlotWindow::runStopped, ui->actionStop, &QAction::trigger);
plotwindow->setWindowTitle("Plots");
plotwindow->setAttribute(Qt::WA_DeleteOnClose);
plotwindow->resize(plotwindow->sizeHint());
plotwindow->show();
plotwindow->showMaximized();
// update every 1 second
QTimer *timer = new QTimer(plotwindow);
connect(timer, &QTimer::timeout, this->plotwindow, QOverload<>::of(&QPlotWindow::redraw));
timer->start(1000);
}
bool MainWindow::handleOpenProj()
{
qDebug() << "Open project clicked";
if (config)
{
// save current settings
config->writeSetup("settings.ini");
// stop current run
onConfigChanged();
}
// select project dir
QFileDialog dialog;
dialog.setWindowTitle("Open a new or existing project");
dialog.setFileMode(QFileDialog::DirectoryOnly);
dialog.setOption(QFileDialog::ShowDirsOnly, false);
if(!dialog.exec())
return false;
QFileInfo proj_dir(dialog.directory().absolutePath());
if (!proj_dir.isDir())
{
QMessageBox::critical(this, "Failed to open direcory", QString("%1 is not a directory.").arg(proj_dir.absolutePath()));
return false;
}
if (!proj_dir.isWritable())
{
QMessageBox::critical(this, "Permission denied", QString("%1 is not writable.").arg(proj_dir.absolutePath()));
return false;
}
// qDebug() << QDir::current();
// if settings.ini does not exist, copy the template settings.ini file to current dir
QString settingsPath = dialog.directory().absolutePath() + "/settings.ini";
if (!dialog.directory().exists("settings.ini"))
{
if(!QFile::copy(":/Data/Data/settings.ini", settingsPath)){
QMessageBox::critical(this, "Cannot create file", QString("Cannot create settings.ini in %1").arg(proj_dir.absolutePath()));
return false;
}
}
// check read permission
if(!QFileInfo(settingsPath).isReadable() && !QFile::setPermissions(settingsPath, QFileDevice::ReadOwner))
{
QMessageBox::critical(this, "Permission denied", QString("Cannot read settings.ini in %1").arg(proj_dir.absolutePath()));
return false;
}
// check write permission
if(!QFileInfo(settingsPath).isWritable() && !QFile::setPermissions(settingsPath, QFileDevice::WriteOwner))
{
QMessageBox::critical(this, "Permission denied", QString("Cannot write to settings.ini in %1").arg(proj_dir.absolutePath()));
return false;
}
// set current path to this dir
QDir::setCurrent(dialog.directory().absolutePath());
// read .ini file in current dir
if (!config) // start up
config = new Setup("settings.ini");
else {
config->readSetup("settings.ini");
}
showConfig();
return true;
}
bool MainWindow::handleSave()
{
qDebug() << "Save clicked";
if (config){
config->writeSetup("settings.ini");
ui->statusBar->showMessage("Project settings saved.");
return true;
}
return false;
}
bool MainWindow::handleSaveAs()
{
qDebug() << "Save as clicked";
if (!config)
return false;
// save current settings
config->writeSetup("settings.ini");
// stop current run
onConfigChanged();
// select new dir
QFileDialog dialog;
dialog.setWindowTitle("Save as");
dialog.setFileMode(QFileDialog::DirectoryOnly);
dialog.setOption(QFileDialog::ShowDirsOnly, false);
if(!dialog.exec())
return false;
QFileInfo proj_dir(dialog.directory().absolutePath());
if (!proj_dir.isDir())
{
QMessageBox::critical(this, "Failed to open direcory", QString("%1 is not a directory.").arg(proj_dir.absolutePath()));
return false;
}
if (!proj_dir.isWritable())
{
QMessageBox::critical(this, "Permission denied", QString("%1 is not writable.").arg(proj_dir.absolutePath()));
return false;
}
// qDebug() << QDir::current();
// if settings.ini does not exist, copy the template settings.ini file to current dir
QString settingsPath = dialog.directory().absolutePath() + "/settings.ini";
if (!dialog.directory().exists("settings.ini"))
{
if(!QFile::copy("settings.ini", settingsPath)){
QMessageBox::critical(this, "Cannot create file", QString("Cannot create settings.ini in %1").arg(proj_dir.absolutePath()));
return false;
}
}
// check read permission
if(!QFileInfo(settingsPath).isReadable() && !QFile::setPermissions(settingsPath, QFileDevice::ReadOwner))
{
QMessageBox::critical(this, "Permission denied", QString("Cannot read settings.ini in %1").arg(proj_dir.absolutePath()));
return false;
}
// check write permission
if(!QFileInfo(settingsPath).isWritable() && !QFile::setPermissions(settingsPath, QFileDevice::WriteOwner))
{
QMessageBox::critical(this, "Permission denied", QString("Cannot write to settings.ini in %1").arg(proj_dir.absolutePath()));
return false;
}
// set current path to this dir
QDir::setCurrent(dialog.directory().absolutePath());
// read .ini file in current dir
config->readSetup("settings.ini");
showConfig();
ui->statusBar->showMessage(QString("Project saved to %1").arg(QDir::currentPath()));
return true;
}
void MainWindow::handleClose()
{
qDebug() << "Close clicked";
this->close();
}
void MainWindow::handleAbout()
{
QMessageBox::about(this, tr("About Application"),
tr("This application is created using Qt 5.13.2. Source code is available at Gitlab."));
// qDebug() << "About clicked";
}
void MainWindow::notifyThreadFinished()
{
ui->statusBar->showMessage("Stopped");
// pop up a message box indicating processing is finished.
// if (!aborted)
// {
// QMessageBox messageBox;
// messageBox.setText("Image reconstruction finished.");
// messageBox.setWindowTitle("Finished");
// messageBox.exec();
// }
}
void MainWindow::handleStart()
{
// if config is changed, or user pressed Stop button,
// workerThread must be null.
// Apply the new settings and start a new run
// If it's not null,
// then resume current run
if (!workerThread.isNull())
{
emit workerStarted();
ui->statusBar->showMessage("Running");
// // save current setting
// config->writeSetup(config->outputDir.absolutePath() + "/settings.ini");
// qDebug() << "Write settings to " << config->outputDir.absolutePath();
}
else{
onConfigApplied();
}
}
void MainWindow::handlePause()
{
if (!workerThread.isNull())
ui->statusBar->showMessage("Paused.");
// // save current setting
// config->writeSetup(config->outputDir.absolutePath() + "/settings.ini");
// qDebug() << "Write settings to " << config->outputDir.absolutePath();
}
void MainWindow::handleStop()
{
if (!workerThread.isNull())
ui->statusBar->showMessage("Stopped.");
// save current setting
config->writeSetup(config->outputDir.absolutePath() + "/settings.ini");
qDebug() << "Write settings to " << config->outputDir.absolutePath();
}
void MainWindow::showConfig()
{
// display settings in settings.ini file
ui->projPathLabel->setText(QDir::currentPath());
ui->filePathLabel->setText(config->filePath);
ui->runIDInput->setText(config->runID);
ui->maxEventNumInput->setText(QString::number(config->maxN));
ui->saveImageBox->setChecked(config->saveImage);
ui->saveSpectrumBox->setChecked(config->saveSpectrum);
ui->saveImageFormat->setCurrentText(config->saveImageFormat);
ui->saveSpectrumFormat->setCurrentText(config->saveSpectrumFormat);
ui->radiusInput->setText(QString::number(config->R, 'f', 4));
ui->phiBinsInput->setText(QString::number(config->phiBins));
ui->phiMinInput->setText(QString::number(config->phiMin * 180 / M_PI, 'f', 4));
ui->phiMaxInput->setText(QString::number(config->phiMax * 180 / M_PI, 'f', 4));
ui->thetaBinsInput->setText(QString::number(config->thetaBins));
ui->thetaMinInput->setText(QString::number(config->thetaMin * 180 / M_PI, 'f', 4));
ui->thetaMaxInput->setText(QString::number(config->thetaMax * 180 / M_PI, 'f', 4));
ui->ergBinsInput->setText(QString::number(config->ergBins));
ui->ergMinInput->setText(QString::number(config->ergMin, 'f', 4));
ui->ergMaxInput->setText(QString::number(config->ergMax, 'f', 4));
ui->enableErgCutBox->setChecked(config->energyCut);
ui->ergCutLowInput->setText(QString::number(config->energyLow, 'f', 4));
ui->ergCutHighInput->setText(QString::number(config->energyUp, 'f', 4));
ui->timeWindowInput->setText(QString::number(config->timeWindow, 'f', 4));
for (int i=0; i<config->channelSettings.size() && i< chNumInputs.size(); i++) {
chNumInputs[i]->setText(QString::number(config->channelSettings[i].chNum));
chNumInputs[i]->setReadOnly(true);
posXInputs[i]->setText(QString::number(config->channelSettings[i].x, 'f', 4));
posXInputs[i]->setReadOnly(true);
posYInputs[i]->setText(QString::number(config->channelSettings[i].y, 'f', 4));
posYInputs[i]->setReadOnly(true);
caliCoefInputs[i]->setText(QString::number(config->channelSettings[i].caliCoef, 'f', 4));
// posXInputs[i]->setReadOnly(true);
chOnBoxes[i]->setChecked(config->channelSettings[i].enabled);
}
}
bool MainWindow::checkConfig()
{
// check if file exists
if (!QFile(config->filePath).exists()){
QMessageBox::critical(this, "File not exist", QString("Cannot open file %1").arg(config->filePath));
return false;
}
// check if runID already exists
if (config->outputDir.exists()) {
// check if it's writable
if (!QFileInfo(config->outputDir.absolutePath()).isWritable())
{
QMessageBox::critical(this, "Permission denied", QString("Cannot write to directory %1").arg(config->outputDir.absolutePath()));
return false;
}
QMessageBox::StandardButton resBtn = QMessageBox::question(this, "Overwrite",
QString("Run-%1 already exists. Are you sure you want to overwrite?\n").arg(config->runID),
QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
QMessageBox::Yes);
if (resBtn != QMessageBox::Yes) {
return false;
}
}
else {
// create a new dir for current ID
if(!config->outputDir.mkpath(".")){
QMessageBox::critical(this, "Permission denied", "Cannot create output directory for run "+config->runID);
return false;
}
// check read permission
QString outdirpath = config->outputDir.absolutePath();
if(!QFileInfo(outdirpath).isReadable() && !QFile::setPermissions(outdirpath, QFileDevice::ReadOwner))
{
QMessageBox::critical(this, "Permission denied", QString("Cannot read settings.ini in %1").arg(outdirpath));
return false;
}
// check write permission
if(!QFileInfo(outdirpath).isWritable() && !QFile::setPermissions(outdirpath, QFileDevice::WriteOwner))
{
QMessageBox::critical(this, "Permission denied", QString("Cannot write to settings.ini in %1").arg(outdirpath));
return false;
}
}
if (config->phiMax <= config->phiMin)
{
QMessageBox::warning(this, "Warning", QString("Min phi must be smaller max theta."));
return false;
}
if (config->thetaMax <= config->thetaMin)
{
QMessageBox::warning(this, "Warning", QString("Min theta must be smaller than max theta."));
return false;
}
if (config->ergMax <= config->ergMin)
{
QMessageBox::warning(this, "Warning", QString("Min energy must be smaller than max energy."));
return false;
}
if (config->energyCut && config->energyUp <= config->energyLow)
{
QMessageBox::warning(this, "Warning", QString("Energy low cut must be smaller than energy high cut."));
return false;
}
// check for duplicates
// lazy nested loop
for (int i=0; i<config->channelSettings.size(); i++) {
for (int j=i+1; j<config->channelSettings.size(); j++) {
if (config->channelSettings[j].chNum == config->channelSettings[i].chNum){
QMessageBox::warning(this, "Duplicated channel number.",
QString("Channel-%1 and channel-%2 have same channel number.").arg(QString::number(i+1), QString::number(j+1)));
return false;
}
}
}
return true;
}
void MainWindow::onConfigChanged()
{
// quit worker thread, save plot data
if (!workerThread.isNull()) {
ui->actionStop->trigger();
gSystem->Sleep(500);
ui->statusBar->showMessage("Stopped.");
}
}
void MainWindow::onConfigApplied()
{
// user press Start button
// if config is not changed, i.e., worker thread is running
// do nothing
if (!workerThread.isNull()){
return;
}
// otherwise, updating config is finished
// check config
if (!checkConfig())
return;
// create plot data if not already
if (!plotdata)
plotdata = new PlotData(config);
else {
// clear plot data
plotdata->clearAll();
}
// check if image space changed
if (config->imageSpacechaged){
if (plotdata){
plotdata->rebinImage();
plotdata->rebinSpectrum();
}
config->imageSpacechaged = false;
}
// pop up plot window
if (plotwindow.isNull() || !plotwindow->isVisible()){
plotwindow = new QPlotWindow(this, config, plotdata);
handleOpenplot();
}
// start worker thread
if (workerThread.isNull())
{
// update image on worker thread
workerThread = new Worker(this, config, plotdata);
connect(workerThread, &Worker::finished, workerThread, &QObject::deleteLater);
connect(workerThread, &Worker::finished, this, &MainWindow::notifyThreadFinished);
connect(this, &MainWindow::workerStarted, workerThread, &Worker::handleStart);
connect(ui->actionPause, &QAction::triggered, workerThread, &Worker::handlePause);
connect(ui->actionStop, &QAction::triggered, workerThread, &Worker::handleStop);
workerThread->start();
}
ui->statusBar->showMessage("Running.");
// // save current setting
// config->writeSetup(config->outputDir.absolutePath() + "/settings.ini");
// qDebug() << "Write settings to " << config->outputDir.absolutePath();
}
// General
void MainWindow::onOpenFileClicked()
{
// open data file for processing
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Data File"), QDir::currentPath(), tr("Text Files (*.txt)"));
if (!fileName.isEmpty() && fileName!=config->filePath){
onConfigChanged();
config->filePath = fileName;
ui->filePathLabel->setText(config->filePath);
}
}
void MainWindow::onRunIDInput()
{
// set run id
QString newid = ui->runIDInput->text();
if (newid != config->runID){
onConfigChanged();
config->runID = newid;
config->outputDir = QDir(newid);
}
}
void MainWindow::onMaxEventNumInput()
{
int eventNum = ui->maxEventNumInput->text().toInt();
if (eventNum != config->maxN){
onConfigChanged();
config->maxN = eventNum;
}
}
// Plot
void MainWindow::onRadiusInput()
{
// set radius of projection sphere
double newradius = ui->radiusInput->text().toDouble();
if (!doubleEqual(newradius, config->R)){
onConfigChanged();
config->R = newradius;
config->imageSpacechaged = true;
}
}
void MainWindow::onPhiBinsInput()
{
int phibins = ui->phiBinsInput->text().toInt();
if (phibins != config->phiBins){
onConfigChanged();
config->phiBins = phibins;
config->imageSpacechaged = true;
}
}
void MainWindow::onPhiMinInput()
{
double phimin = ui->phiMinInput->text().toDouble();
phimin *= M_PI / 180;
if (!doubleEqual(phimin, config->phiMin)){
onConfigChanged();
config->phiMin = phimin;
config->imageSpacechaged = true;
}
}
void MainWindow::onPhiMaxInput()
{
double phimax = ui->phiMaxInput->text().toDouble();
phimax *= M_PI / 180;
if (!doubleEqual(phimax, config->phiMax)){
onConfigChanged();
config->phiMax = phimax;
config->imageSpacechaged = true;
}
}
void MainWindow::onThetaBinsInput()
{
int thetabins = ui->thetaBinsInput->text().toInt();
if (thetabins != config->thetaBins){
onConfigChanged();
config->thetaBins = thetabins;
config->imageSpacechaged = true;
}
}
void MainWindow::onThetaMinInput()
{
double thetamin = ui->thetaMinInput->text().toDouble();
thetamin *= M_PI / 180;
if (!doubleEqual(thetamin, config->thetaMin)){
onConfigChanged();
config->thetaMin = thetamin;
config->imageSpacechaged = true;
}
}
void MainWindow::onThetaMaxInput()
{
double thetamax = ui->thetaMaxInput->text().toDouble();
thetamax *= M_PI / 180;
if (!doubleEqual(thetamax, config->thetaMax)){
onConfigChanged();
config->thetaMax = thetamax;
config->imageSpacechaged = true;
}
}
void MainWindow::onErgBinsInput()
{
int ergBins = ui->ergBinsInput->text().toInt();
if (ergBins != config->ergBins){
onConfigChanged();
config->ergBins = ergBins;
}
}
void MainWindow::onErgMinInput()
{
double ergMin = ui->ergMinInput->text().toDouble();
if (!doubleEqual(ergMin, config->ergMin))
{
onConfigChanged();
config->ergMin = ergMin;
}
}
void MainWindow::onErgMaxInput()
{
double ergMax = ui->ergMaxInput->text().toDouble();
if (!doubleEqual(ergMax, config->ergMax))
{
onConfigChanged();
config->ergMax = ergMax;
}
}
void MainWindow::onErgCutStateChanged()
{
bool ergCutEnabled = ui->enableErgCutBox->isChecked();
if (ergCutEnabled != config->energyCut)
{
onConfigChanged();
config->energyCut = ergCutEnabled;
}
}
void MainWindow::onErgCutLowInput()
{
double ergLow = ui->ergCutLowInput->text().toDouble();
if (!doubleEqual(ergLow, config->energyLow))
{
onConfigChanged();
config->energyLow = ergLow;
}
}
void MainWindow::onErgCutHighInput()
{
double ergHigh = ui->ergCutHighInput->text().toDouble();
if (!doubleEqual(ergHigh, config->energyUp))
{
onConfigChanged();
config->energyUp = ergHigh;
}
}
void MainWindow::onSaveImageStateChanged()
{
bool saveImage = ui->saveImageBox->isChecked();
if (saveImage != config->saveImage)
{
onConfigChanged();
config->saveImage = saveImage;
}
}
void MainWindow::onsaveImageFormatChanged(const QString text)
{
if (text != config->saveImageFormat)
{
onConfigChanged();
config->saveImageFormat = text;
}
}
void MainWindow::onSaveSpectrumStateChanged()
{
bool saveSpectrum = ui->saveSpectrumBox->isChecked();
if (saveSpectrum != config->saveSpectrum)
{
onConfigChanged();
config->saveSpectrum = saveSpectrum;
}
}
void MainWindow::onsaveSpectrumFormatChanged(const QString text)
{
if (text != config->saveSpectrumFormat)
{
onConfigChanged();
config->saveSpectrumFormat = text;
}
}
void MainWindow::onTimeWindowInput()
{
double tmewin = ui->timeWindowInput->text().toDouble();
if (!doubleEqual(tmewin, config->timeWindow))
{
onConfigChanged();
config->timeWindow = tmewin;
}
}
void MainWindow::onChNumInput()
{
// find index of sender
QLineEdit* sender_ = qobject_cast<QLineEdit*>(sender());
if (!sender_)
return;
int newChNum = sender_->text().toInt();
int sender_id = chNumInputs.indexOf(sender_);
qDebug() << "Index of activated entry = " << sender_id;
if (sender_id >= config->channelSettings.size()){
qDebug() << "Add new channel";
// check duplicates
for (int i=0; i<config->channelSettings.size(); i++) {
if (newChNum == config->channelSettings[i].chNum){
QMessageBox::warning(this, "Duplicated channel number.", QString("Channel-%1 and channel-%2 have same channel number.").arg(QString::number(i+1), QString::number(sender_id+1)));
return;
}
}
onConfigChanged();
Channel c;
c.chNum = newChNum;
config->channelSettings.append(c);
}
else if (newChNum != config->channelSettings[sender_id].chNum)
{
onConfigChanged();
qDebug() << "Old channel num is " << config->channelSettings[sender_id].chNum;
config->channelSettings[sender_id].chNum = newChNum;
qDebug() << "New channel num is " << config->channelSettings[sender_id].chNum;
}
}
void MainWindow::onPosXInput()
{
// find index of sender
QLineEdit* sender_ = qobject_cast<QLineEdit*>(sender());
if (!sender_)
return;
double newposx = sender_->text().toDouble();
int sender_id = posXInputs.indexOf(sender_);
qDebug() << "Index of activated entry = " << sender_id;
if (sender_id >= config->channelSettings.size()){
qDebug() << "Add new channel";
onConfigChanged();
Channel c;
c.x = newposx;
config->channelSettings.append(c);
}
else if (!doubleEqual(newposx, config->channelSettings[sender_id].x))
{
onConfigChanged();
qDebug() << "Old x is " << config->channelSettings[sender_id].x;
config->channelSettings[sender_id].x = newposx;
qDebug() << "New x is " << config->channelSettings[sender_id].x;
}
}
void MainWindow::onPosYInput()
{
// find index of sender
QLineEdit* sender_ = qobject_cast<QLineEdit*>(sender());
if (!sender_)
return;
double newposy = sender_->text().toDouble();
int sender_id = posYInputs.indexOf(sender_);
qDebug() << "Index of activated entry = " << sender_id;
if (sender_id >= config->channelSettings.size()){
qDebug() << "Add new channel";
onConfigChanged();
Channel c;
c.y = newposy;
config->channelSettings.append(c);
}
else if (!doubleEqual(newposy, config->channelSettings[sender_id].y))
{
onConfigChanged();
qDebug() << "Old y is " << config->channelSettings[sender_id].y;
config->channelSettings[sender_id].y = newposy;
qDebug() << "New y is " << config->channelSettings[sender_id].y;
}
}
void MainWindow::onCaliCoefInput()
{
// find index of sender
QLineEdit* sender_ = qobject_cast<QLineEdit*>(sender());
if (!sender_)
return;
double newcalicoef = sender_->text().toDouble();
int sender_id = caliCoefInputs.indexOf(sender_);
qDebug() << "Index of activated entry = " << sender_id;
if (sender_id >= config->channelSettings.size()){
qDebug() << "Add new channel";
onConfigChanged();
Channel c;
c.caliCoef = newcalicoef;
config->channelSettings.append(c);
}
else if (!doubleEqual(newcalicoef, config->channelSettings[sender_id].caliCoef))
{
onConfigChanged();
qDebug() << "Old cali coef is " << config->channelSettings[sender_id].caliCoef;
config->channelSettings[sender_id].caliCoef = newcalicoef;
qDebug() << "New cali coef is " << config->channelSettings[sender_id].caliCoef;
}
}
void MainWindow::onChOnStateChanged()
{
// find index of sender
QCheckBox* sender_ = qobject_cast<QCheckBox*>(sender());
if (!sender_)
return;
bool newStat = sender_->isChecked();
int sender_id = chOnBoxes.indexOf(sender_);
qDebug() << "Index of activated entry = " << sender_id;
if (sender_id >= config->channelSettings.size()){
qDebug() << "Add new channel";
onConfigChanged();
Channel c;
c.enabled = newStat;
config->channelSettings.append(c);
}
else if (newStat != config->channelSettings[sender_id].enabled)
{
onConfigChanged();
qDebug() << "Old channel state is " << config->channelSettings[sender_id].enabled;
config->channelSettings[sender_id].enabled = newStat;
qDebug() << "New channelstate is " << config->channelSettings[sender_id].enabled;
}
}
void MainWindow::collectWidgets()
{
chNumInputs.append(ui->channelNumInput_1);
chNumInputs.append(ui->channelNumInput_2);
chNumInputs.append(ui->channelNumInput_3);
chNumInputs.append(ui->channelNumInput_4);
chNumInputs.append(ui->channelNumInput_5);
chNumInputs.append(ui->channelNumInput_6);
chNumInputs.append(ui->channelNumInput_7);
chNumInputs.append(ui->channelNumInput_8);
chNumInputs.append(ui->channelNumInput_9);
chNumInputs.append(ui->channelNumInput_10);
chNumInputs.append(ui->channelNumInput_11);
chNumInputs.append(ui->channelNumInput_12);
chNumInputs.append(ui->channelNumInput_13);
chNumInputs.append(ui->channelNumInput_14);
chNumInputs.append(ui->channelNumInput_15);
chNumInputs.append(ui->channelNumInput_16);
chNumInputs.append(ui->channelNumInput_17);
chNumInputs.append(ui->channelNumInput_18);
chNumInputs.append(ui->channelNumInput_19);
chNumInputs.append(ui->channelNumInput_20);
chNumInputs.append(ui->channelNumInput_21);
chNumInputs.append(ui->channelNumInput_22);
chNumInputs.append(ui->channelNumInput_23);
chNumInputs.append(ui->channelNumInput_24);
chNumInputs.append(ui->channelNumInput_25);
chNumInputs.append(ui->channelNumInput_26);
chNumInputs.append(ui->channelNumInput_27);
chNumInputs.append(ui->channelNumInput_28);
posXInputs.append(ui->posXInput_1);
posXInputs.append(ui->posXInput_2);
posXInputs.append(ui->posXInput_3);
posXInputs.append(ui->posXInput_4);
posXInputs.append(ui->posXInput_5);
posXInputs.append(ui->posXInput_6);
posXInputs.append(ui->posXInput_7);
posXInputs.append(ui->posXInput_8);
posXInputs.append(ui->posXInput_9);
posXInputs.append(ui->posXInput_10);
posXInputs.append(ui->posXInput_11);
posXInputs.append(ui->posXInput_12);
posXInputs.append(ui->posXInput_13);
posXInputs.append(ui->posXInput_14);
posXInputs.append(ui->posXInput_15);
posXInputs.append(ui->posXInput_16);
posXInputs.append(ui->posXInput_17);
posXInputs.append(ui->posXInput_18);
posXInputs.append(ui->posXInput_19);
posXInputs.append(ui->posXInput_20);
posXInputs.append(ui->posXInput_21);
posXInputs.append(ui->posXInput_22);
posXInputs.append(ui->posXInput_23);
posXInputs.append(ui->posXInput_24);
posXInputs.append(ui->posXInput_25);
posXInputs.append(ui->posXInput_26);
posXInputs.append(ui->posXInput_27);
posXInputs.append(ui->posXInput_28);
posYInputs.append(ui->posYInput_1);
posYInputs.append(ui->posYInput_2);
posYInputs.append(ui->posYInput_3);
posYInputs.append(ui->posYInput_4);
posYInputs.append(ui->posYInput_5);
posYInputs.append(ui->posYInput_6);
posYInputs.append(ui->posYInput_7);
posYInputs.append(ui->posYInput_8);
posYInputs.append(ui->posYInput_9);
posYInputs.append(ui->posYInput_10);
posYInputs.append(ui->posYInput_11);
posYInputs.append(ui->posYInput_12);
posYInputs.append(ui->posYInput_13);
posYInputs.append(ui->posYInput_14);
posYInputs.append(ui->posYInput_15);
posYInputs.append(ui->posYInput_16);
posYInputs.append(ui->posYInput_17);
posYInputs.append(ui->posYInput_18);
posYInputs.append(ui->posYInput_19);
posYInputs.append(ui->posYInput_20);
posYInputs.append(ui->posYInput_21);
posYInputs.append(ui->posYInput_22);
posYInputs.append(ui->posYInput_23);
posYInputs.append(ui->posYInput_24);
posYInputs.append(ui->posYInput_25);
posYInputs.append(ui->posYInput_26);
posYInputs.append(ui->posYInput_27);
posYInputs.append(ui->posYInput_28);
chOnBoxes.append(ui->channelOnBox_1);
chOnBoxes.append(ui->channelOnBox_2);
chOnBoxes.append(ui->channelOnBox_3);
chOnBoxes.append(ui->channelOnBox_4);
chOnBoxes.append(ui->channelOnBox_5);
chOnBoxes.append(ui->channelOnBox_6);
chOnBoxes.append(ui->channelOnBox_7);
chOnBoxes.append(ui->channelOnBox_8);
chOnBoxes.append(ui->channelOnBox_9);
chOnBoxes.append(ui->channelOnBox_10);
chOnBoxes.append(ui->channelOnBox_11);
chOnBoxes.append(ui->channelOnBox_12);
chOnBoxes.append(ui->channelOnBox_13);
chOnBoxes.append(ui->channelOnBox_14);
chOnBoxes.append(ui->channelOnBox_15);
chOnBoxes.append(ui->channelOnBox_16);
chOnBoxes.append(ui->channelOnBox_17);
chOnBoxes.append(ui->channelOnBox_18);
chOnBoxes.append(ui->channelOnBox_19);
chOnBoxes.append(ui->channelOnBox_20);
chOnBoxes.append(ui->channelOnBox_21);
chOnBoxes.append(ui->channelOnBox_22);
chOnBoxes.append(ui->channelOnBox_23);
chOnBoxes.append(ui->channelOnBox_24);
chOnBoxes.append(ui->channelOnBox_25);
chOnBoxes.append(ui->channelOnBox_26);
chOnBoxes.append(ui->channelOnBox_27);
chOnBoxes.append(ui->channelOnBox_28);
caliCoefInputs.append(ui->caliCoefInput_1);
caliCoefInputs.append(ui->caliCoefInput_2);
caliCoefInputs.append(ui->caliCoefInput_3);
caliCoefInputs.append(ui->caliCoefInput_4);
caliCoefInputs.append(ui->caliCoefInput_5);
caliCoefInputs.append(ui->caliCoefInput_6);
caliCoefInputs.append(ui->caliCoefInput_7);
caliCoefInputs.append(ui->caliCoefInput_8);
caliCoefInputs.append(ui->caliCoefInput_9);
caliCoefInputs.append(ui->caliCoefInput_10);
caliCoefInputs.append(ui->caliCoefInput_11);
caliCoefInputs.append(ui->caliCoefInput_12);
caliCoefInputs.append(ui->caliCoefInput_13);
caliCoefInputs.append(ui->caliCoefInput_14);
caliCoefInputs.append(ui->caliCoefInput_15);
caliCoefInputs.append(ui->caliCoefInput_16);
caliCoefInputs.append(ui->caliCoefInput_17);
caliCoefInputs.append(ui->caliCoefInput_18);
caliCoefInputs.append(ui->caliCoefInput_19);
caliCoefInputs.append(ui->caliCoefInput_20);
caliCoefInputs.append(ui->caliCoefInput_21);
caliCoefInputs.append(ui->caliCoefInput_22);
caliCoefInputs.append(ui->caliCoefInput_23);
caliCoefInputs.append(ui->caliCoefInput_24);
caliCoefInputs.append(ui->caliCoefInput_25);
caliCoefInputs.append(ui->caliCoefInput_26);
caliCoefInputs.append(ui->caliCoefInput_27);
caliCoefInputs.append(ui->caliCoefInput_28);
}
bool MainWindow::doubleEqual(const double& a, const double & b, const double epsilon)
{
return std::abs(a-b)<=epsilon;
}