357 lines
10 KiB
C++
357 lines
10 KiB
C++
#include "mainwindow.h"
|
|
#include "stretchpanel.h"
|
|
#include <QScrollArea>
|
|
#include <QDir>
|
|
#include <QKeyEvent>
|
|
#include <QMenu>
|
|
#include <QMenuBar>
|
|
#include <QFileDialog>
|
|
#include <QStandardPaths>
|
|
#include <QMessageBox>
|
|
#include <QProgressDialog>
|
|
#include <QDebug>
|
|
#include <QDockWidget>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include "photocapture.h"
|
|
|
|
#ifdef __linux__
|
|
#include <sys/ioctl.h>
|
|
#include <linux/btrfs.h>
|
|
#include <sys/socket.h>
|
|
#include <QSettings>
|
|
#endif
|
|
|
|
int MainWindow::socketPair[2] = {0, 0};
|
|
|
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|
{
|
|
qRegisterMetaType<ImageInfoData>("ImageInfoData");
|
|
qRegisterMetaType<RawImage*>("RawImage");
|
|
|
|
m_info = new ImageInfo(this);
|
|
QDockWidget *infoDock = new QDockWidget(tr("Image info"), this);
|
|
infoDock->setWidget(m_info);
|
|
infoDock->setObjectName("infoDock");
|
|
addDockWidget(Qt::LeftDockWidgetArea, infoDock);
|
|
m_image = new ImageScrollArea(this);
|
|
m_image->resize(0,0);
|
|
//setCentralWidget(m_image);
|
|
resize(800, 600);
|
|
|
|
m_imageGL = new ImageScrollAreaGL(this);
|
|
setCentralWidget(m_imageGL);
|
|
|
|
PhotoCapture *photoCapture = new PhotoCapture(this);
|
|
QDockWidget *captureDock = new QDockWidget(tr("Photo capture"), this);
|
|
captureDock->setWidget(photoCapture);
|
|
captureDock->setObjectName("captureDock");
|
|
addDockWidget(Qt::BottomDockWidgetArea, captureDock);
|
|
|
|
StretchPanel *stretchPanel = new StretchPanel(this);
|
|
connect(stretchPanel, SIGNAL(lowChanged(int)), m_imageGL->imageWidget(), SLOT(setLow(int)));
|
|
connect(stretchPanel, SIGNAL(highChanged(int)), m_imageGL->imageWidget(), SLOT(setHigh(int)));
|
|
connect(stretchPanel, SIGNAL(stretchChanged(int)), m_imageGL->imageWidget(), SLOT(setStrech(int)));
|
|
connect(stretchPanel, SIGNAL(paramChanged(float)), m_imageGL->imageWidget(), SLOT(setStretchParam(float)));
|
|
|
|
QDockWidget *stretchDock = new QDockWidget(tr("Stretch"), this);
|
|
stretchDock->setWidget(stretchPanel);
|
|
stretchDock->setObjectName("strechDock");
|
|
addDockWidget(Qt::LeftDockWidgetArea, stretchDock);
|
|
|
|
setWindowTitle(tr("Tenmon"));
|
|
|
|
m_ringList = new ImageRingList(this);
|
|
connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), this, SLOT(pixmapLoaded(Image*)));
|
|
connect(m_ringList, SIGNAL(currentImageChanged()), this, SLOT(updateWindowTitle()));
|
|
connect(m_ringList, SIGNAL(infoLoaded(ImageInfoData)), m_info, SLOT(setInfo(ImageInfoData)));
|
|
|
|
QMenu *fileMenu = new QMenu(tr("File"), this);
|
|
fileMenu->addAction(tr("Open"), this, SLOT(openFile()), QKeySequence("Ctrl+O"));
|
|
fileMenu->addAction(tr("Copy marked files"), this, SLOT(copyMarked()));
|
|
fileMenu->addAction(tr("Save as"), this, SLOT(saveAs()), QKeySequence("Ctrl+S"));
|
|
QAction *liveModeAction = fileMenu->addAction(tr("Live mode"), this, SLOT(liveMode(bool)));
|
|
liveModeAction->setCheckable(true);
|
|
fileMenu->addAction(tr("Exit"), this, SLOT(close()));
|
|
menuBar()->addMenu(fileMenu);
|
|
|
|
QMenu *viewMenu = new QMenu(tr("View"), this);
|
|
viewMenu->addAction(tr("Zoom In"), m_imageGL, SLOT(zoomIn()), QKeySequence::ZoomIn);
|
|
viewMenu->addAction(tr("Zoom Out"), m_imageGL, SLOT(zoomOut()), QKeySequence::ZoomOut);
|
|
viewMenu->addAction(tr("Best Fit"), m_imageGL, SLOT(bestFit()), QKeySequence("Ctrl+1"));
|
|
viewMenu->addAction(tr("100%"), m_imageGL, SLOT(oneToOne()));
|
|
menuBar()->addMenu(viewMenu);
|
|
|
|
QMenu *selectMenu = new QMenu(tr("Select"), this);
|
|
selectMenu->addAction(tr("Mark"), this, SLOT(markImage()), Qt::Key_F5);
|
|
selectMenu->addAction(tr("Unmark"), this, SLOT(unmarkImage()), Qt::Key_F8);
|
|
selectMenu->addSeparator();
|
|
selectMenu->addAction(tr("Mark and next"), this, SLOT(markAndNext()), Qt::Key_M);
|
|
selectMenu->addAction(tr("Unmark and next"), this, SLOT(unmarkAndNext()), Qt::Key_X);
|
|
menuBar()->addMenu(selectMenu);
|
|
|
|
QMenu *analyzeMenu = new QMenu(tr("Analyze"), this);
|
|
QActionGroup *analyzeGroup = new QActionGroup(this);
|
|
connect(analyzeGroup, &QActionGroup::triggered, [](QAction* action) {
|
|
static QAction* lastAction = nullptr;
|
|
if(action == lastAction)
|
|
{
|
|
action->setChecked(false);
|
|
lastAction = nullptr;
|
|
}
|
|
else
|
|
lastAction = action;
|
|
});
|
|
|
|
QAction *statsAction = analyzeGroup->addAction(tr("Image statistics"));
|
|
QAction *peakAction = analyzeGroup->addAction(tr("Peak finder"));
|
|
QAction *starAction = analyzeGroup->addAction("Star finder");
|
|
statsAction->setCheckable(true);
|
|
peakAction->setCheckable(true);
|
|
starAction->setCheckable(true);
|
|
connect(statsAction, SIGNAL(toggled(bool)), this, SLOT(imageStats(bool)));
|
|
connect(peakAction, SIGNAL(toggled(bool)), this, SLOT(peakFinder(bool)));
|
|
connect(starAction, SIGNAL(toggled(bool)), this, SLOT(starFinder(bool)));
|
|
analyzeMenu->addActions({statsAction, peakAction, starAction});
|
|
menuBar()->addMenu(analyzeMenu);
|
|
|
|
m_database = new Database(this);
|
|
if(!m_database->init())
|
|
QMessageBox::critical(this, tr("Can't open DB"), tr("Can't open SQLITE database"));
|
|
|
|
QMenu *dockMenu = new QMenu(tr("Docks"), this);
|
|
dockMenu->addAction(infoDock->toggleViewAction());
|
|
dockMenu->addAction(captureDock->toggleViewAction());
|
|
dockMenu->addAction(stretchDock->toggleViewAction());
|
|
menuBar()->addMenu(dockMenu);
|
|
|
|
setupSigterm();
|
|
QSettings settings;
|
|
restoreGeometry(settings.value("mainwindow/geometry").toByteArray());
|
|
restoreState(settings.value("mainwindow/state").toByteArray());
|
|
|
|
QStringList standardLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
|
|
if(standardLocations.size())
|
|
_lastDir = standardLocations.first();
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
}
|
|
|
|
void MainWindow::keyPressEvent(QKeyEvent *event)
|
|
{
|
|
switch (event->key())
|
|
{
|
|
case Qt::Key_Left:
|
|
m_ringList->decrement();
|
|
break;
|
|
case Qt::Key_Right:
|
|
m_ringList->increment();
|
|
break;
|
|
default:
|
|
event->ignore();
|
|
break;
|
|
}
|
|
|
|
if(event->isAccepted())
|
|
updateWindowTitle();
|
|
}
|
|
|
|
void MainWindow::keyReleaseEvent(QKeyEvent *event)
|
|
{
|
|
event->ignore();
|
|
}
|
|
|
|
void MainWindow::setupSigterm()
|
|
{
|
|
#ifdef __linux__
|
|
struct sigaction signal;
|
|
|
|
signal.sa_handler = MainWindow::signalHandler;
|
|
sigemptyset(&signal.sa_mask);
|
|
signal.sa_flags = 0;
|
|
signal.sa_flags |= SA_RESTART;
|
|
|
|
sigaction(SIGHUP, &signal, 0);
|
|
sigaction(SIGTERM, &signal, 0);
|
|
sigaction(SIGINT, &signal, 0);
|
|
|
|
::socketpair(AF_UNIX, SOCK_STREAM, 0, socketPair);
|
|
socketNotifier = new QSocketNotifier(socketPair[1], QSocketNotifier::Read, this);
|
|
connect(socketNotifier, SIGNAL(activated(int)), this, SLOT(socketNotify()));
|
|
#endif
|
|
}
|
|
|
|
void MainWindow::signalHandler(int)
|
|
{
|
|
char a = 1;
|
|
::write(socketPair[0], &a, sizeof(a));
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
QSettings settings;
|
|
settings.setValue("mainwindow/geometry", saveGeometry());
|
|
settings.setValue("mainwindow/state", saveState());
|
|
QMainWindow::closeEvent(event);
|
|
}
|
|
|
|
void MainWindow::socketNotify()
|
|
{
|
|
socketNotifier->setEnabled(false);
|
|
char tmp;
|
|
read(socketPair[1], &tmp, sizeof(tmp));
|
|
close();
|
|
socketNotifier->setEnabled(true);
|
|
}
|
|
|
|
void MainWindow::pixmapLoaded(Image *image)
|
|
{
|
|
m_image->setImage(image->pixmap());
|
|
if(image->rawImage())
|
|
{
|
|
m_imageGL->setImage(image->rawImage());
|
|
}
|
|
else
|
|
{
|
|
m_imageGL->setImage(image->pixmap());
|
|
}
|
|
}
|
|
|
|
void MainWindow::openFile()
|
|
{
|
|
QString file = QFileDialog::getOpenFileName(this, tr("Open file"), _lastDir, tr("Images (*.jpg *.png *.cr2 *.fit *.fits *.JPG *.PNG *.CR2 *.FIT *.FITS)"));
|
|
if(!file.isEmpty())
|
|
{
|
|
QFileInfo info(file);
|
|
m_ringList->setFile(info.canonicalFilePath());
|
|
updateWindowTitle();
|
|
_lastDir = QFileInfo(file).absoluteDir().absolutePath();
|
|
}
|
|
}
|
|
|
|
void MainWindow::saveAs()
|
|
{
|
|
QString file = QFileDialog::getSaveFileName(this, tr("Save as"), _lastDir, tr("Images (*.jpg *.png *.JPG *.PNG)"));
|
|
if(!file.isEmpty())
|
|
{
|
|
QImage img = m_imageGL->imageWidget()->renderToImage();
|
|
if(!img.isNull())
|
|
img.save(file);
|
|
}
|
|
}
|
|
|
|
void MainWindow::markImage()
|
|
{
|
|
ImagePtr ptr = m_ringList->currentImage();
|
|
if(ptr)
|
|
{
|
|
QString file = ptr->name();
|
|
if(!file.isEmpty())
|
|
m_database->mark(file);
|
|
|
|
updateWindowTitle();
|
|
}
|
|
}
|
|
|
|
void MainWindow::unmarkImage()
|
|
{
|
|
ImagePtr ptr = m_ringList->currentImage();
|
|
if(ptr)
|
|
{
|
|
QString file = ptr->name();
|
|
if(!file.isEmpty())
|
|
m_database->unmark(file);
|
|
|
|
updateWindowTitle();
|
|
}
|
|
}
|
|
|
|
void MainWindow::markAndNext()
|
|
{
|
|
markImage();
|
|
m_ringList->increment();
|
|
updateWindowTitle();
|
|
}
|
|
|
|
void MainWindow::unmarkAndNext()
|
|
{
|
|
unmarkImage();
|
|
m_ringList->increment();
|
|
updateWindowTitle();
|
|
}
|
|
|
|
void MainWindow::copyMarked()
|
|
{
|
|
QString dest = QFileDialog::getExistingDirectory(this, tr("Select destination"));
|
|
QDir dir(dest);
|
|
if(!dest.isEmpty() && dir.exists())
|
|
{
|
|
int i = 0;
|
|
QStringList files = m_database->getMarkedFiles();
|
|
QProgressDialog progress(tr("Copying"), tr("Cancel"), 0, files.size(), this);
|
|
progress.setWindowModality(Qt::WindowModal);
|
|
progress.show();
|
|
foreach(const QString &file, files)
|
|
{
|
|
QFileInfo info(file);
|
|
QFile srcFile(file);
|
|
QFile dstFile(dir.absoluteFilePath(info.fileName()));
|
|
|
|
if(dstFile.exists())
|
|
continue;
|
|
|
|
if(progress.wasCanceled())
|
|
break;
|
|
#ifdef __linux__
|
|
srcFile.open(QIODevice::ReadOnly);
|
|
dstFile.open(QIODevice::WriteOnly);
|
|
if(ioctl(dstFile.handle(), BTRFS_IOC_CLONE, srcFile.handle()) < 0)
|
|
{
|
|
dstFile.remove();
|
|
dstFile.close();
|
|
qDebug() << dstFile.fileName();
|
|
srcFile.copy(dstFile.fileName());
|
|
}
|
|
#else
|
|
srcFile.copy(dstFile.fileName());
|
|
#endif
|
|
progress.setValue(i++);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::liveMode(bool active)
|
|
{
|
|
m_ringList->setLiveMode(active);
|
|
}
|
|
|
|
void MainWindow::imageStats(bool imageStats)
|
|
{
|
|
m_ringList->setCalculateStats(imageStats);
|
|
}
|
|
|
|
void MainWindow::peakFinder(bool findPeaks)
|
|
{
|
|
m_ringList->setFindPeaks(findPeaks);
|
|
}
|
|
|
|
void MainWindow::starFinder(bool findStars)
|
|
{
|
|
m_ringList->setFindStars(findStars);
|
|
}
|
|
|
|
void MainWindow::updateWindowTitle()
|
|
{
|
|
ImagePtr ptr = m_ringList->currentImage();
|
|
if(ptr)
|
|
{
|
|
QFileInfo info(ptr->name());
|
|
QString title = info.fileName();
|
|
if(m_database->isMarked(ptr->name()))
|
|
title += " *";
|
|
setWindowTitle(title);
|
|
}
|
|
}
|