907 lines
32 KiB
C++
907 lines
32 KiB
C++
/***********************************************************************
|
|
* This file is part of Scanned Image Extract.
|
|
*
|
|
* Scanned Image Extract is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Scanned Image Extract is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Scanned Image Extract. If not, see <http://www.gnu.org/licenses/>
|
|
*
|
|
*
|
|
* Copyright (C) 2015, Dominik Rueß; info@dominik-ruess.de
|
|
**********************************************************************/
|
|
|
|
#include "mainwindow.h"
|
|
#include "ui_mainwindow.h"
|
|
|
|
#include <QDate>
|
|
#include <QDateTime>
|
|
#include <QWhatsThis>
|
|
#include <QPolygonF>
|
|
#include <QtWidgets/QFileDialog>
|
|
#include <QSettings>
|
|
#include <QImage>
|
|
#include <QImageReader>
|
|
#include <QFileInfo>
|
|
#include <QFileInfoList>
|
|
#include <QDebug>
|
|
#include <QTimer>
|
|
#include <QMessageBox>
|
|
#include <QProgressDialog>
|
|
#include <QTextBrowser>
|
|
#include <QCheckBox>
|
|
#include <QPushButton>
|
|
#include <QShortcut>
|
|
|
|
#include "pQPixmap.h"
|
|
|
|
#include "imageboundary.h"
|
|
#include "TargetImage.h"
|
|
|
|
#include "settings.h"
|
|
|
|
MainWindow::MainWindow(QWidget *parent):
|
|
QMainWindow(parent),
|
|
ui(new Ui::MainWindow),
|
|
_dialogLock(false),
|
|
_title(tr("Scanned Image Extractor")),
|
|
_targetWait(0),
|
|
_tearDown(false)
|
|
{
|
|
ui->setupUi(this);
|
|
qRegisterMetaType<QFileInfoList>("QFileInfoList");
|
|
qRegisterMetaType<SourceFilePtr>("SourceFilePtr");
|
|
qRegisterMetaType<TargetImagePtr>("TargetImagePtr");
|
|
|
|
ui->graphicsView_Source->setScene(&_scene);
|
|
_scene.init();
|
|
connect(&_scene, SIGNAL(doneCopying(QString,QString)), SLOT(doneCopy(QString,QString)));
|
|
|
|
setWindowTitle(_title);
|
|
|
|
connect(ui->actionLoad_Directory, SIGNAL(triggered()),
|
|
this, SLOT(_onLoadFile()));
|
|
connect(&_scene, SIGNAL(changed(bool)), this, SLOT(currImageHasChanges(bool)), Qt::QueuedConnection);
|
|
connect(&_scene, SIGNAL(selectedAspect(float)), this, SLOT(toggleAspect(float)), Qt::QueuedConnection);
|
|
connect(&_scene, SIGNAL(numSelected(int)), this, SLOT(numSelectionChanged(int)), Qt::QueuedConnection);
|
|
connect(this, SIGNAL(newList(QFileInfoList,int)),
|
|
&_scene, SLOT(newImageList(QFileInfoList,int)), Qt::QueuedConnection);
|
|
|
|
statusBar()->showMessage(tr("Hover the mouse pointer over an element to get help"));
|
|
|
|
|
|
QSettings settings(tr(IMAGE_ORGANIZATION_ORG), tr(IMAGE_ORGANIZATION_APP));
|
|
restoreGeometry(settings.value("mainwin_geom").toByteArray());
|
|
ui->splitter->restoreState(settings.value("mainwin_splitter").toByteArray());
|
|
ui->doubleSpinBox_cropInitial->setValue(settings.value("cropdistance", 2.0).toDouble());
|
|
ui->doubleSpinBox_crop->setValue(settings.value("cropdistance", 3.0).toDouble());
|
|
ui->lineEdit_aspectRatio->setText(settings.value("manualaspect", "4:3").toString());
|
|
ui->graphicsView_Target->setScene(&_sceneTarget);
|
|
|
|
connect(ui->checkBox_enforceAspect, SIGNAL(toggled(bool)), &_scene, SLOT(setEnforceAspect(bool)), Qt::QueuedConnection);
|
|
|
|
ui->checkBox_enforceAspect->setChecked(settings.value("enforceAspectNextIm", true).toBool());
|
|
|
|
|
|
connect(&_scene, SIGNAL(updateTargetDisplay(QPixmap)),
|
|
this, SLOT(_onNewTargetImage(QPixmap)), Qt::QueuedConnection);
|
|
|
|
connect(&_scene, SIGNAL(rotation90(Rotation90)),
|
|
this, SLOT(_onRotation90(Rotation90)), Qt::QueuedConnection);
|
|
|
|
connect(this, SIGNAL(newOrientation(Rotation90)),
|
|
&_scene, SLOT(newRotation(Rotation90)), Qt::QueuedConnection);
|
|
|
|
connect(&_scene, SIGNAL(resetAspect()), this, SLOT(_resetAspect()), Qt::QueuedConnection);
|
|
|
|
connect(&_scene, SIGNAL(filePosition(QString)), ui->label_imagePosition, SLOT(setText(QString)), Qt::QueuedConnection);
|
|
connect(&_scene, SIGNAL(targetPosition(QString)), ui->label_targetPosition, SLOT(setText(QString)), Qt::QueuedConnection);
|
|
|
|
connect(ui->doubleSpinBox_crop, SIGNAL(valueChanged(double)),
|
|
&_scene, SLOT(newIndividualCrop(double)), Qt::QueuedConnection);
|
|
|
|
connect(ui->splitter, SIGNAL(splitterMoved(int,int)),
|
|
this, SLOT(_updateTargetView(int,int)), Qt::QueuedConnection);
|
|
|
|
connect(ui->radioButton_1_1, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_2_1, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_3_1, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_3_2, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_4_3, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_5_3, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_5_4, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_16_9, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_free, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->radioButton_manual, SIGNAL(toggled(bool)), this, SLOT(_getAspectRatio()));
|
|
connect(ui->lineEdit_aspectRatio, SIGNAL(textChanged(QString)), this, SLOT(_getAspectRatio()));
|
|
// connect(ui->lineEdit_aspectRatio, SIGNAL(textEdited(QString)), this, SLOT(_getAspectRatio()));
|
|
|
|
connect(this, SIGNAL(newAspectRatio(double)),
|
|
&_scene, SLOT(newAspectRatio(double)), Qt::QueuedConnection);
|
|
|
|
ui->radioButton_rot0->setChecked(true);
|
|
|
|
ui->graphicsView_Source->setBackgroundBrush( QPalette().dark() );//QBrush(IMAGE_BACKGROUND_COLOR));
|
|
ui->graphicsView_Target->setBackgroundBrush(QPalette().dark());//QBrush(IMAGE_BACKGROUND_COLOR));
|
|
|
|
//_getAspectRatio();
|
|
|
|
connect(&_scene, SIGNAL(fileName(const QString)),
|
|
ui->label_filename, SLOT(setText(QString)), Qt::QueuedConnection);
|
|
connect(&_scene, SIGNAL(fileName(const QString)), SLOT(newFileName(QString)), Qt::QueuedConnection);
|
|
connect(&_scene, SIGNAL(noAspect()), SLOT(noAspect()), Qt::QueuedConnection);
|
|
connect(&_scene, SIGNAL(noRotation()), SLOT(noRotation()), Qt::QueuedConnection);
|
|
connect(&_scene, SIGNAL(noCrop()), SLOT(noCrop()), Qt::QueuedConnection);
|
|
|
|
if (QIcon::hasThemeIcon("go-first"))
|
|
ui->toolButton_firstImage->setIcon(QIcon::fromTheme("go-first"));
|
|
if (QIcon::hasThemeIcon("go-last"))
|
|
ui->toolButton_lastImage->setIcon(QIcon::fromTheme("go-last"));
|
|
if (QIcon::hasThemeIcon("go-next"))
|
|
{
|
|
ui->toolButton_nextImage->setIcon(QIcon::fromTheme("go-next"));
|
|
ui->toolButton_nextItem->setIcon(QIcon::fromTheme("go-next"));
|
|
}
|
|
if (QIcon::hasThemeIcon("go-previous"))
|
|
{
|
|
ui->toolButton_prevImage->setIcon(QIcon::fromTheme("go-previous"));
|
|
ui->toolButton_prevItem->setIcon(QIcon::fromTheme("go-previous"));
|
|
}
|
|
|
|
if (QIcon::hasThemeIcon("zoom-in"))
|
|
ui->toolButton_zoomIn->setIcon(QIcon::fromTheme("zoom-in"));
|
|
if (QIcon::hasThemeIcon("zoom-out"))
|
|
ui->toolButton_zoomOut->setIcon(QIcon::fromTheme("zoom-out"));
|
|
if (QIcon::hasThemeIcon("zoom-original"))
|
|
ui->toolButton_zoomOriginal->setIcon(QIcon::fromTheme("zoom-original"));
|
|
if (QIcon::hasThemeIcon("zoom-fit-best"))
|
|
ui->toolButton_zoomFit->setIcon(QIcon::fromTheme("zoom-fit-best"));
|
|
|
|
if (QIcon::hasThemeIcon("view-refresh"))
|
|
ui->toolButton_refresh->setIcon(QIcon::fromTheme("view-refresh"));
|
|
if (QIcon::hasThemeIcon("help"))
|
|
ui->toolButton_Help->setIcon(QIcon::fromTheme("help"));
|
|
|
|
connect(ui->toolButton_refresh, SIGNAL(clicked()), &_scene, SLOT(refreshView()), Qt::QueuedConnection);
|
|
|
|
|
|
// check for update after two minutes
|
|
QTimer::singleShot( WAIT_FOR_DONATE_HINT_MS, this, SLOT(on_actionSupport_by_donation_triggered()) );
|
|
QTimer::singleShot( WAIT_FOR_CHECK_FOR_UPDATE, this, SLOT(on_actionCheck_for_new_version_triggered()) );
|
|
|
|
connect (&_settings, SIGNAL(newValues()), this, SLOT(newValues()), Qt::QueuedConnection);
|
|
|
|
connect (&_scene, SIGNAL(reloadSettings()), this, SLOT(loadSettings()), Qt::QueuedConnection);
|
|
connect (&_scene, SIGNAL(newCrop(double)), SLOT(onNewCrop(double)), Qt::QueuedConnection);
|
|
connect (&_scene, SIGNAL(setTargetWaiting(bool)), SLOT(setWaitTarget(bool)), Qt::QueuedConnection);
|
|
|
|
enableButtons();
|
|
newValues();
|
|
_scene.newIndividualCrop(ui->doubleSpinBox_crop->value());
|
|
|
|
if (!settings.value("starthelp", false).toBool())
|
|
{
|
|
QTimer::singleShot(2000, this, SLOT(on_actionOnline_Help_triggered()));
|
|
}
|
|
settings.setValue("starthelp", true);
|
|
|
|
|
|
new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_A), this, SLOT(selectAll()));
|
|
|
|
_getAspectRatio();
|
|
}
|
|
|
|
void MainWindow::_onLoadFile()
|
|
{
|
|
QSettings settings(tr(IMAGE_ORGANIZATION_ORG), tr(IMAGE_ORGANIZATION_APP));
|
|
|
|
QStringList filters;
|
|
filters << "*.jpg" << "*.jpeg" << "*.tiff" << "*.tif" << "*.bmp" << "*.png" << "*.gif" << "*.pbm" << "*.pgm" << "*.ppm";
|
|
|
|
const QString filename = QFileDialog::getOpenFileName(this,
|
|
tr("Load Image"),
|
|
settings.value("lastDir").toString(),
|
|
tr("Images (%1)").arg(filters.join(" ")));
|
|
|
|
if (filename.length() > 0) {
|
|
QFileInfo info(filename);
|
|
|
|
settings.setValue("lastDir", info.absolutePath());
|
|
|
|
QFileInfoList otherimages;
|
|
QDir dir(info.absolutePath());
|
|
otherimages = dir.entryInfoList(filters);
|
|
|
|
int index = -1;
|
|
for (int i=0; i<(int)otherimages.size(); i++) {
|
|
if (otherimages.at(i).fileName() == info.fileName()) {
|
|
index = i;
|
|
}
|
|
}
|
|
|
|
emit newList(otherimages, index);
|
|
}
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
_tearDown = true;
|
|
disconnect(this);
|
|
disconnect(&_scene);
|
|
disconnect(&_sceneTarget);
|
|
QSettings settings(tr(IMAGE_ORGANIZATION_ORG), tr(IMAGE_ORGANIZATION_APP));
|
|
settings.setValue("mainwin_geom", saveGeometry());
|
|
settings.setValue("mainwin_splitter", ui->splitter->saveState());
|
|
settings.setValue("cropdistance", ui->doubleSpinBox_cropInitial->value());
|
|
settings.setValue("manualaspect", ui->lineEdit_aspectRatio->text());
|
|
settings.setValue("enforceAspectNextIm", ui->checkBox_enforceAspect->isChecked());
|
|
|
|
delete ui;
|
|
}
|
|
|
|
void MainWindow::_onNewTargetImage(const QPixmap& pixmap)
|
|
{
|
|
if (_tearDown) return;
|
|
|
|
if (_sceneTarget.items().size() > 0)
|
|
{
|
|
for (int i=_sceneTarget.items().size()-1; i>=0; i--) {
|
|
QGraphicsItem* item = _sceneTarget.items()[i];
|
|
_sceneTarget.removeItem(item);
|
|
delete item;
|
|
}
|
|
}
|
|
|
|
QGraphicsPixmapItem* pixItem = new QGraphicsPixmapItem(pixmap);
|
|
_sceneTarget.addItem(pixItem);
|
|
|
|
_updateTargetView();
|
|
}
|
|
|
|
void MainWindow::_updateTargetView(int, int)
|
|
{
|
|
|
|
if (_sceneTarget.items().size() > 0) {
|
|
|
|
_sceneTarget.setSceneRect(_sceneTarget.items()[0]->boundingRect());
|
|
ui->graphicsView_Target->centerOn(_sceneTarget.items()[0]);
|
|
ui->graphicsView_Target->fitInView(_sceneTarget.items()[0],
|
|
Qt::KeepAspectRatio);
|
|
ui->graphicsView_Target->scale(0.95,0.95);
|
|
ui->graphicsView_Target->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
ui->graphicsView_Target->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
}
|
|
}
|
|
|
|
void MainWindow::_onRotation90(const Rotation90 rotation)
|
|
{
|
|
switch (rotation) {
|
|
case TargetRotation0:
|
|
ui->radioButton_rot0->setChecked(true);
|
|
break;
|
|
case TargetRotation90:
|
|
ui->radioButton_rot90->setChecked(true);
|
|
break;
|
|
case TargetRotation180:
|
|
ui->radioButton_rot180->setChecked(true);
|
|
break;
|
|
case TargetRotation270:
|
|
ui->radioButton_rot270->setChecked(true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_radioButton_rot0_toggled(bool isChecked)
|
|
{
|
|
if (isChecked) emit newOrientation(TargetRotation0);
|
|
}
|
|
|
|
void MainWindow::on_radioButton_rot90_toggled(bool isChecked)
|
|
{
|
|
if (isChecked) emit newOrientation(TargetRotation90);
|
|
}
|
|
|
|
void MainWindow::on_radioButton_rot180_toggled(bool isChecked)
|
|
{
|
|
if (isChecked) emit newOrientation(TargetRotation180);
|
|
}
|
|
|
|
void MainWindow::on_radioButton_rot270_toggled(bool isChecked)
|
|
{
|
|
if (isChecked) emit newOrientation(TargetRotation270);
|
|
}
|
|
|
|
void MainWindow::on_toolButton_deleteItem_clicked()
|
|
{
|
|
_scene.deleteSelection();
|
|
}
|
|
|
|
void MainWindow::on_toolButton_prevItem_clicked()
|
|
{
|
|
_scene.nextTarget(-1);
|
|
}
|
|
|
|
void MainWindow::on_toolButton_nextItem_clicked()
|
|
{
|
|
_scene.nextTarget(1);
|
|
}
|
|
|
|
void MainWindow::_getAspectRatio()
|
|
{
|
|
double aspectRatio = -1;
|
|
if (ui->radioButton_16_9->isChecked()) {
|
|
aspectRatio = 16.0/9.0;
|
|
} else if (ui->radioButton_1_1->isChecked()) {
|
|
aspectRatio = 1.000001;
|
|
} else if (ui->radioButton_2_1->isChecked()) {
|
|
aspectRatio = 2.0;
|
|
} else if (ui->radioButton_3_1->isChecked()) {
|
|
aspectRatio = 3.0/1.0;
|
|
} else if (ui->radioButton_3_2->isChecked()) {
|
|
aspectRatio = 3.0/2.0;
|
|
} else if (ui->radioButton_4_1->isChecked()) {
|
|
aspectRatio = 4.0/1.0;
|
|
} else if (ui->radioButton_4_3->isChecked()) {
|
|
aspectRatio = 4.0/3.0;
|
|
} else if (ui->radioButton_5_3->isChecked()) {
|
|
aspectRatio = 5.0/3.0;
|
|
} else if (ui->radioButton_5_4->isChecked()) {
|
|
aspectRatio = 5.0/4.0;
|
|
} else if (ui->radioButton_manual->isChecked()) {
|
|
QString ratioStr = ui->lineEdit_aspectRatio->text();
|
|
const int pos = ratioStr.indexOf(":");
|
|
if (pos > 0) {
|
|
const double part1 = ratioStr.left(pos).toDouble();
|
|
const double part2 = ratioStr.right(ratioStr.length() -pos -1).toDouble();
|
|
if (part1 > 0 && part2 > 0) {
|
|
aspectRatio = part1 / part2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aspectRatio = ratioStr.toFloat();
|
|
}
|
|
}
|
|
|
|
emit newAspectRatio(aspectRatio);
|
|
}
|
|
|
|
void MainWindow::toggleAspect(const float aspectNew)
|
|
{
|
|
const float minDiff = 0.001;
|
|
float aspect = aspectNew;
|
|
if (aspect < 1.0 && aspect > 0) {
|
|
aspect = 1.0/aspect;
|
|
}
|
|
if (qAbs(aspect - 16.0/9.0) < minDiff){
|
|
ui->radioButton_16_9->setChecked(true);
|
|
} else if (qAbs(aspect - 1.0) < minDiff) {
|
|
ui->radioButton_1_1->setChecked(true);
|
|
} else if (qAbs(aspect - 2.0) < minDiff) {
|
|
ui->radioButton_2_1->setChecked(true);
|
|
} else if (qAbs(aspect - 3.0) < minDiff) {
|
|
ui->radioButton_3_1->setChecked(true);
|
|
} else if (qAbs(aspect - 3.0/2.0) < minDiff) {
|
|
ui->radioButton_3_2->setChecked(true);
|
|
} else if (qAbs(aspect - 4.0) < minDiff) {
|
|
ui->radioButton_4_1->setChecked(true);
|
|
} else if (qAbs(aspect - 4.0/3.0) < minDiff) {
|
|
ui->radioButton_4_3->setChecked(true);
|
|
} else if (qAbs(aspect - 5.0/3.0) < minDiff) {
|
|
ui->radioButton_5_3->setChecked(true);
|
|
} else if (qAbs(aspect - 5.0/4.0) < minDiff) {
|
|
ui->radioButton_5_4->setChecked(true);
|
|
} else if (aspect > 0)
|
|
{
|
|
ui->radioButton_manual->setChecked(true);
|
|
ui->lineEdit_aspectRatio->setText(QString("%1").arg(aspect));
|
|
}
|
|
else
|
|
{
|
|
ui->radioButton_free->setChecked(true);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_toolButton_zoomIn_clicked()
|
|
{
|
|
_scene.zoom(1.25);
|
|
}
|
|
|
|
void MainWindow::on_toolButton_zoomOut_clicked()
|
|
{
|
|
_scene.zoom(0.8);
|
|
}
|
|
|
|
void MainWindow::on_toolButton_zoomFit_clicked()
|
|
{
|
|
_scene.zoomFit();
|
|
}
|
|
|
|
void MainWindow::on_toolButton_zoomOriginal_clicked()
|
|
{
|
|
_scene.zoom1();
|
|
}
|
|
|
|
void MainWindow::on_toolButton_firstImage_clicked()
|
|
{
|
|
_scene.loadPosition(0);
|
|
enableButtons();
|
|
}
|
|
|
|
void MainWindow::on_toolButton_lastImage_clicked()
|
|
{
|
|
|
|
_scene.loadPosition(-2);
|
|
enableButtons();
|
|
}
|
|
|
|
void MainWindow::on_toolButton_nextImage_clicked()
|
|
{
|
|
|
|
_scene.loadPosition(1, true);
|
|
enableButtons();
|
|
}
|
|
|
|
void MainWindow::resizeEvent(QResizeEvent *)
|
|
{
|
|
_updateTargetView();
|
|
}
|
|
|
|
void MainWindow::on_toolButton_prevImage_clicked()
|
|
{
|
|
|
|
_scene.loadPosition(-1, true);
|
|
enableButtons();
|
|
}
|
|
|
|
void MainWindow::on_toolButton_saveTargtes_clicked()
|
|
{
|
|
bool save = true;
|
|
bool force = false;
|
|
if (ui->toolButton_saveTargtes->styleSheet().length() > 0)
|
|
{
|
|
QMessageBox::StandardButton reply = QMessageBox::question(this, tr("Already saved"),
|
|
tr("The images have already been extracted for this scan, "
|
|
" do you want to save them again?"),
|
|
QMessageBox::Yes|QMessageBox::Abort);
|
|
save = reply == QMessageBox::Yes;
|
|
force = save;
|
|
|
|
}
|
|
if (save)
|
|
{
|
|
_scene.saveCurrent(true, force);
|
|
}
|
|
}
|
|
|
|
|
|
void MainWindow::_resetAspect()
|
|
{
|
|
ui->radioButton_free->setChecked(true);
|
|
}
|
|
|
|
void MainWindow::on_actionAbout_Qt_triggered()
|
|
{
|
|
qApp->aboutQt();
|
|
}
|
|
|
|
void MainWindow::on_action_About_triggered()
|
|
{
|
|
_about.setModal(true);
|
|
_about.setVersion(version_scannerExtract.getVersionMajor(),
|
|
version_scannerExtract.getVersionMinor(),
|
|
version_scannerExtract.getVersionPatch(),
|
|
version_scannerExtract.getCompilerBits());
|
|
_about.show();
|
|
}
|
|
|
|
void MainWindow::on_actionSupport_by_donation_triggered()
|
|
{
|
|
const QString donateText = _about.getDonateText();
|
|
const QString donateTitle = tr("Support Scanned Image Extractor");
|
|
|
|
if (sender() == ui->actionSupport_by_donation) {
|
|
QMessageBox::information(this,
|
|
donateTitle,
|
|
donateText);
|
|
} else {
|
|
// if first time: save date:
|
|
// otherwise: check if one week has passed and asked for donation
|
|
QSettings settings(tr(IMAGE_ORGANIZATION_ORG), tr(IMAGE_ORGANIZATION_APP));
|
|
const int firstTimeYear = 2000;
|
|
QDateTime firstTime = settings.value("firsttimestarteddonation",
|
|
QDateTime(QDate(firstTimeYear,1,1),
|
|
QTime::currentTime())).toDateTime();
|
|
if (firstTime.date().year() == firstTimeYear)
|
|
{
|
|
settings.setValue("firsttimestarteddonation", QDateTime::currentDateTime());
|
|
} else if (QDateTime::currentDateTime().addDays(DAYS_UNTIL_DONATE_HINT) > firstTime ){
|
|
if (!lockDialog()) {
|
|
QTimer::singleShot(10000, this, SLOT(on_actionSupport_by_donation_triggered()));
|
|
return;
|
|
}
|
|
provideInfo(donateTitle, donateText, tr("donatehint"));
|
|
unlockDialog();
|
|
settings.setValue("firsttimestarteddonation", QDateTime::currentDateTime());
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionCheck_for_new_version_triggered()
|
|
{
|
|
qint32 major, minor, patch;
|
|
QString link, text;
|
|
bool connection;
|
|
|
|
QProgressDialog* bar = NULL;
|
|
if (sender() == ui->actionCheck_for_new_version) {
|
|
bar = new QProgressDialog(tr("Retrieving version data"), tr("asdf"), 0, 0, this);
|
|
bar->setCancelButton(0);
|
|
bar->show();
|
|
}
|
|
|
|
//QDataStream data(reply);
|
|
|
|
const bool result = version_scannerExtract.checkForUpdateVersion(NEW_VERSION_LOCATION_SCANNER_EXTRACT,
|
|
NEW_VERSION_MAGIC_NUMBER,
|
|
major,
|
|
minor,
|
|
patch,
|
|
link,
|
|
text,
|
|
connection);
|
|
if (bar != NULL) {
|
|
bar->close();
|
|
bar->deleteLater();
|
|
}
|
|
|
|
// only show once a week
|
|
QSettings settings(tr(IMAGE_ORGANIZATION_ORG), tr(IMAGE_ORGANIZATION_APP));
|
|
settings.setValue("main_geometry", saveGeometry());
|
|
QDate lastHint = settings.value("lastShowUpdate", QDate(1950,1,1)).toDate();
|
|
QDate oneWeekBack = QDate::currentDate().addDays(-7);
|
|
const bool autoCheck = lastHint < oneWeekBack || sender() == ui->actionCheck_for_new_version;
|
|
|
|
if (result && autoCheck)
|
|
{
|
|
QDialog *diag = new QDialog(this);
|
|
diag->setModal(true);
|
|
QVBoxLayout* layH = new QVBoxLayout();
|
|
diag->setLayout(layH);
|
|
diag->layout()->addWidget(new QLabel(tr("New version of <i>Scanned Image Extractor</i> available: <b>%1.%2.%3</b> (current: %4.%5.%6)").arg(major).arg(minor).arg(patch).arg(version_scannerExtract.getVersionMajor()).arg(version_scannerExtract.getVersionMinor()).arg(version_scannerExtract.getVersionPatch())));
|
|
QLabel* dlLabel = new QLabel(QString(tr("Download: <a href=\"%1\">%2</a>")).arg(link).arg(link));
|
|
dlLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
|
|
dlLabel->setOpenExternalLinks(true);
|
|
diag->layout()->addWidget(dlLabel);
|
|
diag->layout()->addWidget(new QLabel(tr("<b>Changelog:</b>")));
|
|
QTextBrowser* tb = new QTextBrowser();
|
|
tb->setText(text);
|
|
tb->setReadOnly(true);
|
|
diag->layout()->addWidget(tb);
|
|
QPushButton *okay = new QPushButton(tr("close"));
|
|
connect(okay, SIGNAL(clicked()), diag, SLOT(deleteLater()));
|
|
QHBoxLayout *lay = new QHBoxLayout();
|
|
lay->addStretch();
|
|
lay->addWidget(okay);
|
|
lay->addStretch();
|
|
layH->addLayout(lay);
|
|
diag->show();
|
|
settings.setValue("lastShowUpdate", QDate::currentDate());
|
|
} else {
|
|
if (!connection && sender() == ui->actionCheck_for_new_version) {
|
|
QMessageBox::warning(this, tr("no connection"), tr("Was not able to connect to new version data server. Please check manually"), QMessageBox::Ok);
|
|
} else if (sender() == ui->actionCheck_for_new_version) {
|
|
QMessageBox::information(this, tr("no update necessary"), tr("There is no new version of Scanned Image Extractor!"), QMessageBox::Ok);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::provideInfo(
|
|
const QString &headline,
|
|
const QString &text,
|
|
const QString& settingsValue,
|
|
const QString& showAgain,
|
|
const int width,
|
|
const int minWidth)
|
|
{
|
|
QSettings settings(qApp->translate("tools", IMAGE_ORGANIZATION_ORG), qApp->translate("tools", IMAGE_ORGANIZATION_APP));
|
|
if (!settings.value(settingsValue, true).toBool()) {
|
|
return;
|
|
}
|
|
|
|
const int iconsize = 128;
|
|
|
|
QDialog* dialog = new QDialog(this, Qt::Dialog);
|
|
dialog->setMinimumWidth(minWidth);
|
|
dialog->setMaximumWidth(width);
|
|
dialog->setModal(true);
|
|
dialog->setWindowTitle(headline);
|
|
QVBoxLayout* layout = new QVBoxLayout;
|
|
QHBoxLayout* messageInfo = new QHBoxLayout;
|
|
|
|
QIcon icon;
|
|
if (QIcon::hasThemeIcon("info")) {
|
|
icon = QIcon::fromTheme("info");
|
|
} else {
|
|
icon = QIcon(":/images/info.png");
|
|
}
|
|
QLabel* infoIcon = new QLabel;
|
|
infoIcon->setScaledContents(false);
|
|
pQPixmap pixmap (icon.pixmap(256,
|
|
QIcon::Normal,
|
|
QIcon::On));
|
|
infoIcon->setPixmap(pixmap->scaled(QSize(iconsize, iconsize),
|
|
Qt::KeepAspectRatio,
|
|
Qt::SmoothTransformation));
|
|
infoIcon->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
|
|
|
QLabel* info = new QLabel(text);
|
|
info->setOpenExternalLinks(true);
|
|
info->setTextFormat(Qt::RichText);
|
|
info->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
|
|
info->setWordWrap(true);
|
|
#ifndef _WIN32
|
|
info->setMargin(5);
|
|
#endif
|
|
info->setMaximumWidth(width-iconsize);
|
|
messageInfo->addWidget(infoIcon);
|
|
messageInfo->addWidget(info);
|
|
|
|
QHBoxLayout* layoutCheckBox = new QHBoxLayout;
|
|
layoutCheckBox->addStretch();
|
|
QCheckBox* showAgainBox = new QCheckBox(showAgain);
|
|
showAgainBox->setChecked(true);
|
|
showAgainBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
|
layoutCheckBox->addWidget(showAgainBox);
|
|
|
|
QHBoxLayout* layoutButton = new QHBoxLayout;
|
|
layoutButton->addStretch();
|
|
|
|
QPushButton* okButton = new QPushButton(qApp->translate("tools", "OK"));
|
|
layoutButton->addWidget(okButton);
|
|
#ifndef _WIN32
|
|
layoutButton->setMargin(5);
|
|
#endif
|
|
qApp->connect(okButton, SIGNAL(clicked()), dialog, SLOT(close()));
|
|
|
|
|
|
layout->addLayout(messageInfo);
|
|
layout->addLayout(layoutCheckBox);
|
|
layout->addLayout(layoutButton);
|
|
dialog->setLayout(layout);
|
|
|
|
dialog->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
|
|
|
dialog->exec();
|
|
|
|
settings.setValue(settingsValue, showAgainBox->isChecked());
|
|
|
|
delete dialog;
|
|
dialog = 0;
|
|
}
|
|
|
|
bool MainWindow::lockDialog()
|
|
{
|
|
if (_dialogLock) {
|
|
return false;
|
|
}
|
|
_dialogLock = true;
|
|
return true;
|
|
}
|
|
|
|
void MainWindow::unlockDialog()
|
|
{
|
|
_dialogLock = false;
|
|
}
|
|
|
|
void MainWindow::enableButtons()
|
|
{
|
|
bool isFirst, isLast;
|
|
_scene.getIsFirstLast(isFirst, isLast);
|
|
ui->toolButton_nextImage->setEnabled(!isLast);
|
|
ui->toolButton_lastImage->setEnabled(!isLast);
|
|
ui->toolButton_firstImage->setEnabled(!isFirst);
|
|
ui->toolButton_prevImage->setEnabled(!isFirst);
|
|
}
|
|
|
|
void MainWindow::currImageHasChanges(bool hasChanges)
|
|
{
|
|
if (hasChanges)
|
|
{
|
|
ui->toolButton_saveTargtes->setStyleSheet("");
|
|
ui->toolButton_saveTargtes->setEnabled(true);
|
|
}
|
|
else
|
|
{
|
|
ui->toolButton_saveTargtes->setStyleSheet("background-color:#AA88EE55;");
|
|
//ui->toolButton_saveTargtes->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
void MainWindow::newFileName(const QString filename)
|
|
{
|
|
setWindowTitle(_title + " - " + filename);
|
|
enableButtons();
|
|
}
|
|
|
|
void MainWindow::on_action_Settings_triggered()
|
|
{
|
|
_settings.show();
|
|
}
|
|
|
|
void MainWindow::loadSettings()
|
|
{
|
|
_scene.setDestination(_settings.getTargetDir());
|
|
_scene.setPrefix(_settings.getPrefix());
|
|
|
|
_scene.setThresh(_settings.getThresh());
|
|
_scene.setMaxAspect(_settings.getMaxAspect());
|
|
_scene.setLevels(_settings.getLevels() );
|
|
_scene.setMaxOverlap(_settings.getMinArea());
|
|
_scene.setMinArea(_settings.getMinArea());
|
|
_scene.setMinAreaWithinImage(_settings.getMinAreaWithinImage());
|
|
_scene.setSplitMaxOffset(_settings.getSplitMaxoffsetFrac());
|
|
_scene.setSplitMinCornerDist(_settings.getSplitMinCornerDist());
|
|
_scene.setSplitMinLengthFrac(_settings.getSplitMinLengthFrac());
|
|
_scene.setMaximumHierarchyLevel(_settings.getMaxHierarchyLevel());
|
|
_scene.setNumPreLoad(_settings.getNumPreLoad());
|
|
}
|
|
|
|
void MainWindow::newValues()
|
|
{
|
|
loadSettings();
|
|
_scene.reloadFromNewSettings();
|
|
}
|
|
|
|
|
|
void MainWindow::onNewCrop(const double crop)
|
|
{
|
|
ui->doubleSpinBox_crop->setValue(crop*100.0);
|
|
}
|
|
|
|
|
|
void MainWindow::noRotation()
|
|
{
|
|
QListIterator<QObject *> i(ui->groupBox_orientation->children());
|
|
while (i.hasNext())
|
|
{
|
|
QObject* item = i.next();
|
|
QRadioButton* b = dynamic_cast<QRadioButton*>( item );
|
|
if (b > 0 && b->isChecked()) {
|
|
b->setAutoExclusive(false);
|
|
b->setChecked(false);
|
|
b->setAutoExclusive(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::noAspect()
|
|
{
|
|
QListIterator<QObject *> i(ui->groupBox_aspect->children());
|
|
while (i.hasNext())
|
|
{
|
|
QRadioButton* b = dynamic_cast<QRadioButton*>( i.next());
|
|
if (b > 0 && b->isChecked()) {
|
|
b->setAutoExclusive(false);
|
|
b->setChecked(false);
|
|
b->setAutoExclusive(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::noCrop()
|
|
{
|
|
ui->doubleSpinBox_crop->setValue(0);
|
|
}
|
|
|
|
void MainWindow::setWaitTarget(const bool wait)
|
|
{
|
|
if (wait) {
|
|
if (_targetWait == 0) {
|
|
_targetWait = new QProgressBar(ui->graphicsView_Target);
|
|
_targetWait->setMaximum(0);
|
|
_targetWait->setMinimum(0);
|
|
_targetWait->show();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_targetWait != 0) {
|
|
_targetWait->setVisible(false);
|
|
delete _targetWait;
|
|
_targetWait = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::on_actionAbout_liblbfgs_triggered()
|
|
{
|
|
QMessageBox::information(this,
|
|
tr("liblbfgs"),
|
|
tr("<a href=\"http://www.chokkan.org/software/liblbfgs/\">liblbfgs</a> is an optimization/energy minimization library which implements the"
|
|
" Limited-memory Broyden-Fletcher-Goldfarb-Shanno algorithm (L-BFGS)."
|
|
"Copyright (c) 2002-2014 by Naoaki Okazaki - <a href=\"http://opensource.org/licenses/mit-license.php\">MIT license</a>"),
|
|
QMessageBox::Ok);
|
|
|
|
|
|
}
|
|
|
|
void MainWindow::on_doubleSpinBox_cropInitial_valueChanged(const double val)
|
|
{
|
|
_scene.initialCropChanged(val/100.0);
|
|
}
|
|
|
|
void MainWindow::numSelectionChanged(const int num)
|
|
{
|
|
ui->doubleSpinBox_crop->setEnabled(num > 0);
|
|
ui->doubleSpinBox_cropInitial->setEnabled(num == 0);
|
|
}
|
|
|
|
|
|
void MainWindow::doneCopy(const QString& filename,
|
|
const QString& targetLocation)
|
|
{
|
|
statusBar()->showMessage(QString(tr("finished copying '%1' to '%2'")).arg(filename).arg(targetLocation),
|
|
5000);
|
|
}
|
|
|
|
void MainWindow::on_actionOnline_Help_triggered()
|
|
{
|
|
_helpDialog.show();
|
|
/*
|
|
QMessageBox::information(this,
|
|
tr("Help"),getHelpText(),
|
|
QMessageBox::Ok);*/
|
|
}
|
|
|
|
QString MainWindow::getHelpText()
|
|
{
|
|
|
|
return tr("Find the online help at <a href=\"http://dominik-ruess.de/scannerExtract\">dominik-ruess.de/scannerExtract</a>"
|
|
"<br><br>"
|
|
"<b>Workflow:</b><ol>"
|
|
"<li>load a scanned image</li>"
|
|
"<li>the system will suggest photographs, you can now:<ol>"
|
|
"<li>accept the suggestion(s)</li>"
|
|
"<li>manipulate suggestions: <ul><li>drag corner or edge of rectangles</li>"
|
|
"<li>press CTRL for symmetric change</li>"
|
|
"<li>keep SHIFT pressed before dragging corner, this rotates the rectangle</li></ul></li>"
|
|
"<li>add new rectangle: deselect all (click somewhere empty). Click on a photograph corner, keep mouse clicked and drag line to a second corner. Then move/resize the new rectangle and click to release.</li>"
|
|
"</ol></li>"
|
|
"<li>the rectangles will be saved automatically when you go to the next scanned image</li></ol>"
|
|
"<b>Keyboard shortcuts:</b><br><table>"
|
|
"<tr><td>Keys 0-9</td><td> select aspect ratios</td></tr>"
|
|
"<tr><td>Keys 'a', 's', 'd' and 'f'</td><td> change orientation of current target</td></tr>"
|
|
"<tr><td>Keys CTRL+V and CTRL+B</td><td> navigate to prev. and next input image</td></tr>"
|
|
"<tr><td>Keys N, M and delete</td><td> navigate prev. and next target or delete target</td></tr></table>");
|
|
}
|
|
|
|
void MainWindow::showStartupHelp()
|
|
{
|
|
provideInfo(tr("Startup Hint"), getHelpText(), tr("startupHelp"));
|
|
}
|
|
|
|
void MainWindow::on_toolButton_Help_clicked()
|
|
{
|
|
QWhatsThis::enterWhatsThisMode();
|
|
}
|
|
|
|
void MainWindow::on_actionAbout_Open_CV_triggered()
|
|
{
|
|
QMessageBox::information(this,
|
|
tr("About OpenCV"),
|
|
tr("<a href=\"http://opencv.org\">OpenCV</a> a powerful and free (BSD-License) computer vision library."
|
|
" Scanned Image Extractor can use version 2 or 3 of OpenCV."
|
|
" Copyright (c) 2015 by <a href=\"http://itseez.com/\">itseez</a>"),
|
|
QMessageBox::Ok);
|
|
}
|