Compare commits

..

18 Commits

Author SHA1 Message Date
nou a4cfc65d4b Wrap reindex into transaction 2022-05-20 22:57:36 +02:00
nou b4746be190 Update help about marking images 2022-05-20 22:41:00 +02:00
nou 9ceb7556f9 Add marking and unmark from thumbnails view 2022-05-20 22:27:53 +02:00
nou 41b29f0701 Show marked files in database view 2022-05-20 12:10:06 +02:00
nou 67ae2d4b62 Mark unmark files from database view 2022-05-20 11:07:18 +02:00
nou b6b6863331 Add override keyword 2022-05-20 10:34:23 +02:00
nou 571fa57af2 Update translations 2022-05-19 09:58:01 +02:00
nou abb3d631bf Double click in file tree open file 2022-05-19 09:51:47 +02:00
nou b65911943e Fix in context menu 2022-05-19 09:47:42 +02:00
nou 9d9f8db499 Fix crash 2022-05-18 17:43:19 +02:00
nou 3060b17c0c Translations update 2022-05-18 17:39:59 +02:00
nou fcf336d63a Second call to QTranslator::load() seem to clear translation 2022-05-18 17:34:15 +02:00
nou 54ef8e990c Selecting thumbnails 2022-05-18 17:33:20 +02:00
nou 94466a6b9b Draw file name under thumbnail 2022-05-09 22:56:06 +02:00
nou b84d8127ad Add copy, move and index action to File tree 2022-05-09 18:14:10 +02:00
nou c971a919ec Add Filetree dock 2022-05-09 15:58:23 +02:00
nou 8c248b7cfc Add French tranlation, credit Patrick Chevalley 2022-05-08 00:18:42 +02:00
nou 43b510a78c Try load translation from application dir 2022-05-08 00:16:11 +02:00
28 changed files with 993 additions and 100 deletions
+3
View File
@@ -65,6 +65,9 @@ Following the slider are 5 buttons for automatic stretching:
This dialog can be useful to clear marks from images. Marked images show a <b>*</b> character in the title bar of the main window. This dialog can be useful to clear marks from images. Marked images show a <b>*</b> character in the title bar of the main window.
Marked images can be copied or moved to a selected directory with <i>File->Copy/Move marked files</i>. Marked images can be copied or moved to a selected directory with <i>File->Copy/Move marked files</i>.
After copying or moving, the list of marked files is cleared. The list of marked files will be remembered after quitting the program.</p> After copying or moving, the list of marked files is cleared. The list of marked files will be remembered after quitting the program.</p>
<p>Another way to mark images is in database view where you can select rows and then select mark or unmark action in context menu. Marked
files will be shown with bold text. Third way to mark files is from thumnails view where you can press press <i>Shift</i> and click with left
mouse button and drag across thumbnails to mark them. Holding <i>Ctrl</i> will unmark files.</p>
<h3>Database of FITS/XISF files</h3> <h3>Database of FITS/XISF files</h3>
<p>Tenmon can scan a directory of FITS/XISF files and index metadata from FITS headers into it's internal database. This allows searching and sorting images based on that metadata.</p> <p>Tenmon can scan a directory of FITS/XISF files and index metadata from FITS headers into it's internal database. This allows searching and sorting images based on that metadata.</p>
+4
View File
@@ -59,6 +59,10 @@ Posledné tlačidlo zapína a vypína nastavovanie optimálnych hodnôt úrovní
obrázkoch zobrazuje znak * v záhlaví hlavného okna. Takto označené obrázky je potom možné skopírovať alebo obrázkoch zobrazuje znak * v záhlaví hlavného okna. Takto označené obrázky je potom možné skopírovať alebo
presunúť do vybraného adresára pomocou <i>Súbor->Skopírovať/Presunúť označené súbory</i>. Po skopírovaní alebo presunúť do vybraného adresára pomocou <i>Súbor->Skopírovať/Presunúť označené súbory</i>. Po skopírovaní alebo
presunutú sa zoznam označených obrázkov vymaže. Program si tento zoznam pamätá aj po svojom ukončení.</p> presunutú sa zoznam označených obrázkov vymaže. Program si tento zoznam pamätá aj po svojom ukončení.</p>
<p>Ďalší spôsob ako označiť obrázky je cez databázu FITS/XISF kde je možné vybrať jednotlivé riadky. Potom stačí
vybrať označit alebo odznačiť v kontextovom menu. Označené súbory budú zobrazené tučným textom. Tretí spôsob na označenie
obrázkov je možné cez náhľady. Držaním <i>Shift</i> a následne kliknutím ľavým tlačítkom myši sa daný obrázok označí.
Pre odznačenie je treba držať <i>Ctrl</i></p>
<h3>Databáza FITS/XISF súborov</h3> <h3>Databáza FITS/XISF súborov</h3>
<p>Program vie prehľadať adresár a indexovať meta údaje z FIST a XISF obrázkov do internej databázy v ktorej sa dá <p>Program vie prehľadať adresár a indexovať meta údaje z FIST a XISF obrázkov do internej databázy v ktorej sa dá
+21
View File
@@ -76,6 +76,20 @@ bool Database::unmark(const QString &filename)
return checkError(m_unmarkQuery); return checkError(m_unmarkQuery);
} }
bool Database::mark(const QStringList &filenames)
{
m_markQuery.bindValue(0, filenames);
m_markQuery.execBatch();
return checkError(m_markQuery);
}
bool Database::unmark(const QStringList &filenames)
{
m_unmarkQuery.bindValue(0, filenames);
m_unmarkQuery.execBatch();
return checkError(m_unmarkQuery);
}
bool Database::isMarked(const QString &filename) bool Database::isMarked(const QString &filename)
{ {
m_isMarkedQuery.bindValue(":name", filename); m_isMarkedQuery.bindValue(":name", filename);
@@ -143,6 +157,7 @@ void Database::reindex(QProgressDialog *progress)
{ {
QVariantList deleteids; QVariantList deleteids;
QSqlDatabase database = QSqlDatabase::database(); QSqlDatabase database = QSqlDatabase::database();
database.transaction();
QSqlQuery files = database.exec("SELECT id,file,mtime FROM fits_files"); QSqlQuery files = database.exec("SELECT id,file,mtime FROM fits_files");
progress->setMaximum(files.size()); progress->setMaximum(files.size());
int i = 0; int i = 0;
@@ -155,10 +170,16 @@ void Database::reindex(QProgressDialog *progress)
if(!file.exists()) if(!file.exists())
deleteids.append(files.value(0)); deleteids.append(files.value(0));
progress->setValue(i++); progress->setValue(i++);
if(progress->wasCanceled())
{
database.rollback();
return;
}
} }
QSqlQuery deleteFiles("DELETE FROM fits_files WHERE id = ?", database); QSqlQuery deleteFiles("DELETE FROM fits_files WHERE id = ?", database);
deleteFiles.bindValue(0, deleteids); deleteFiles.bindValue(0, deleteids);
deleteFiles.execBatch(); deleteFiles.execBatch();
database.commit();
} }
QStringList Database::getFitsKeywords() QStringList Database::getFitsKeywords()
+2
View File
@@ -26,6 +26,8 @@ public:
bool init(); bool init();
bool mark(const QString &filename); bool mark(const QString &filename);
bool unmark(const QString &filename); bool unmark(const QString &filename);
bool mark(const QStringList &filenames);
bool unmark(const QStringList &filenames);
bool isMarked(const QString &filename); bool isMarked(const QString &filename);
QStringList getMarkedFiles(); QStringList getMarkedFiles();
void clearMarkedFiles(); void clearMarkedFiles();
+85 -5
View File
@@ -6,6 +6,8 @@
#include <QHeaderView> #include <QHeaderView>
#include <QSqlError> #include <QSqlError>
#include <QDebug> #include <QDebug>
#include <QMenu>
#include <QContextMenuEvent>
#include <iostream> #include <iostream>
const QStringList DEFAULT_COLUMNS = {"EXPTIME", "OBJECT", "RA", "DEC"}; const QStringList DEFAULT_COLUMNS = {"EXPTIME", "OBJECT", "RA", "DEC"};
@@ -47,9 +49,9 @@ QStringList SelectColumnsDialog::selectedColumns()
return ret; return ret;
} }
FITSFileModel::FITSFileModel(QObject *parent) : QSqlQueryModel(parent) FITSFileModel::FITSFileModel(Database *database, QObject *parent) : QSqlQueryModel(parent)
, m_database(database)
{ {
} }
void FITSFileModel::sort(int column, Qt::SortOrder order) void FITSFileModel::sort(int column, Qt::SortOrder order)
@@ -86,6 +88,44 @@ void FITSFileModel::setFilter(const QStringList &key, const QStringList &value)
prepareQuery(); prepareQuery();
} }
QVariant FITSFileModel::data(const QModelIndex &index, int role) const
{
if(role == Qt::FontRole && index.column() == 0)
{
QFont font;
QString file = index.data().toString();
font.setBold(m_markedFiles.contains(file));
return font;
}
return QSqlQueryModel::data(index, role);
}
void FITSFileModel::filesMarked(const QModelIndexList &indexes)
{
for(auto &index : indexes)
{
QString file = index.data().toString();
if(!m_markedFiles.contains(file))
{
m_markedFiles.insert(file);
emit dataChanged(index, index, {Qt::FontRole});
}
}
}
void FITSFileModel::filesUnmarked(const QModelIndexList &indexes)
{
for(auto &index : indexes)
{
QString file = index.data().toString();
if(m_markedFiles.contains(file))
{
m_markedFiles.remove(file);
emit dataChanged(index, index, {Qt::FontRole});
}
}
}
void FITSFileModel::prepareQuery() void FITSFileModel::prepareQuery()
{ {
QString cols; QString cols;
@@ -122,6 +162,31 @@ void FITSFileModel::prepareQuery()
std::cout << sql.toStdString() << std::endl; std::cout << sql.toStdString() << std::endl;
if(lastError().type() != QSqlError::NoError) if(lastError().type() != QSqlError::NoError)
qDebug() << lastError(); qDebug() << lastError();
m_markedFiles = m_database->getMarkedFiles().toSet();
}
DatabaseTableView::DatabaseTableView(QWidget *parent) : QTableView(parent)
{
}
void DatabaseTableView::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu;
QAction *mark = menu.addAction(tr("Mark"));
QAction *unmark = menu.addAction(tr("Unmark"));
QAction *a = menu.exec(event->globalPos());
if(a == nullptr)
return;
QModelIndexList indexes = selectionModel()->selectedRows();
if(a == mark)
emit filesMarked(indexes);
else if(a == unmark)
emit filesUnmarked(indexes);
} }
DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent) DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent)
@@ -130,14 +195,15 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
QVBoxLayout *layout = new QVBoxLayout(this); QVBoxLayout *layout = new QVBoxLayout(this);
setLayout(layout); setLayout(layout);
m_tableView = new QTableView(this); m_tableView = new DatabaseTableView(this);
m_tableView->verticalHeader()->setDefaultSectionSize(1); m_tableView->verticalHeader()->setDefaultSectionSize(1);
m_tableView->setSortingEnabled(true); m_tableView->setSortingEnabled(true);
m_tableView->horizontalHeader()->setSortIndicatorShown(true); m_tableView->horizontalHeader()->setSortIndicatorShown(true);
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
layout->addWidget(m_tableView); layout->addWidget(m_tableView);
connect(m_tableView, &QTableView::activated, this, &DataBaseView::itemActivated); connect(m_tableView, &QTableView::activated, this, &DataBaseView::itemActivated);
m_model = new FITSFileModel(this); m_model = new FITSFileModel(m_database, this);
QSettings settings; QSettings settings;
m_tableView->setModel(m_model); m_tableView->setModel(m_model);
@@ -151,6 +217,21 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
hlayout->addWidget(selectColumnsButton); hlayout->addWidget(selectColumnsButton);
connect(selectColumnsButton, &QPushButton::pressed, this, &DataBaseView::selectColumns); connect(selectColumnsButton, &QPushButton::pressed, this, &DataBaseView::selectColumns);
connect(m_tableView, &DatabaseTableView::filesMarked, [this](QModelIndexList indexes){
QStringList files;
for(auto &index : indexes)
files.append(index.data().toString());
m_database->mark(files);
m_model->filesMarked(indexes);
});
connect(m_tableView, &DatabaseTableView::filesUnmarked, [this](QModelIndexList indexes){
QStringList files;
for(auto &index : indexes)
files.append(index.data().toString());
m_database->unmark(files);
m_model->filesUnmarked(indexes);
});
for(int i=0; i<3; i++) for(int i=0; i<3; i++)
{ {
m_filterKeyword[i] = new QComboBox(this); m_filterKeyword[i] = new QComboBox(this);
@@ -214,4 +295,3 @@ void DataBaseView::applyFilter()
} }
m_model->setFilter(keys, values); m_model->setFilter(keys, values);
} }
+22 -5
View File
@@ -15,7 +15,7 @@ class SelectColumnsDialog : public QDialog
Q_OBJECT Q_OBJECT
QListWidget *m_listWidget; QListWidget *m_listWidget;
public: public:
SelectColumnsDialog(QWidget *parent = nullptr); explicit SelectColumnsDialog(QWidget *parent = nullptr);
void setColumns(QStringList columns); void setColumns(QStringList columns);
QStringList selectedColumns(); QStringList selectedColumns();
}; };
@@ -27,26 +27,43 @@ class FITSFileModel : public QSqlQueryModel
QString m_sort; QString m_sort;
QStringList m_key; QStringList m_key;
QStringList m_value; QStringList m_value;
QSet<QString> m_markedFiles;
Database *m_database;
public: public:
FITSFileModel(QObject *parent = nullptr); explicit FITSFileModel(Database *database, QObject *parent = nullptr);
void sort(int column, Qt::SortOrder order); void sort(int column, Qt::SortOrder order) override;
void setColumns(const QStringList &columns); void setColumns(const QStringList &columns);
void setFilter(const QStringList &key, const QStringList &value); void setFilter(const QStringList &key, const QStringList &value);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void filesMarked(const QModelIndexList &indexes);
void filesUnmarked(const QModelIndexList &indexes);
protected: protected:
void prepareQuery(); void prepareQuery();
}; };
class DatabaseTableView : public QTableView
{
Q_OBJECT
public:
explicit DatabaseTableView(QWidget *parent = nullptr);
protected:
void contextMenuEvent(QContextMenuEvent *event) override;
signals:
void filesMarked(QModelIndexList indexes);
void filesUnmarked(QModelIndexList indexes);
};
class DataBaseView : public QWidget class DataBaseView : public QWidget
{ {
Q_OBJECT Q_OBJECT
Database *m_database; Database *m_database;
QTableView *m_tableView; DatabaseTableView *m_tableView;
FITSFileModel *m_model; FITSFileModel *m_model;
QComboBox *m_filterKeyword[3]; QComboBox *m_filterKeyword[3];
QLineEdit *m_search[3]; QLineEdit *m_search[3];
public: public:
explicit DataBaseView(Database *database, QWidget *parent = nullptr); explicit DataBaseView(Database *database, QWidget *parent = nullptr);
~DataBaseView(); ~DataBaseView() override;
public slots: public slots:
void selectColumns(); void selectColumns();
void loadDatabase(); void loadDatabase();
+98
View File
@@ -1,6 +1,10 @@
#include "filesystemwidget.h" #include "filesystemwidget.h"
#include <QSettings> #include <QSettings>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QContextMenuEvent>
#include <QMenu>
#include <QSettings>
#include <QHeaderView>
FilesystemWidget::FilesystemWidget(QAbstractItemModel *model, QWidget *parent) : QWidget(parent) FilesystemWidget::FilesystemWidget(QAbstractItemModel *model, QWidget *parent) : QWidget(parent)
, m_model(model) , m_model(model)
@@ -34,3 +38,97 @@ void FilesystemWidget::fileClicked(const QModelIndex &index)
{ {
emit fileSelected(index.row()); emit fileSelected(index.row());
} }
Filetree::Filetree(QWidget *parent) : QTreeView(parent)
{
QSettings settings;
m_rootDir = settings.value("filetree/rootDir", QDir::homePath()).toString();
m_fileSystemModel = new QFileSystemModel(this);
m_fileSystemModel->setRootPath(m_rootDir);
m_fileSystemModel->setNameFilters({"*.fits", "*.fit", "*.xisf", "*.jpg", "*.jpeg", "*.png"});
m_fileSystemModel->setNameFilterDisables(false);
setModel(m_fileSystemModel);
setRootIndex(m_fileSystemModel->index(m_rootDir));
header()->restoreState(settings.value("filetree/header").toByteArray());
}
Filetree::~Filetree()
{
QSettings settings;
settings.setValue("filetree/rootDir", m_rootDir);
settings.setValue("filetree/header", header()->saveState());
}
void Filetree::contextMenuEvent(QContextMenuEvent *event)
{
QModelIndex index = indexAt(event->pos());
QFileInfo info = m_fileSystemModel->fileInfo(index);
QMenu menu;
QAction *open = nullptr;
QAction *setRoot = nullptr;
QAction *copy = nullptr;
QAction *move = nullptr;
QAction *indexDir = nullptr;
if(info.isFile())
open = menu.addAction(tr("Open"));
if(info.isDir())
{
open = menu.addAction(tr("Open"));
setRoot = menu.addAction(tr("Set as root"));
copy = menu.addAction(tr("Copy marked files"));
move = menu.addAction(tr("Move marked files"));
indexDir = menu.addAction(tr("Index directory"));
}
menu.addSeparator();
QAction *resetRoot = menu.addAction(tr("Reset root"));
QAction *goUp = menu.addAction(tr("Go up"));
QAction *a = menu.exec(event->globalPos());
if(a == nullptr)
return;
if(a == open)
{
emit fileSelected(m_fileSystemModel->filePath(index));
}
else if(a == setRoot && index.isValid())
{
setRootIndex(index);
m_rootDir = m_fileSystemModel->filePath(index);
}
else if(a == resetRoot)
{
setRootIndex(QModelIndex());
m_rootDir = QDir::rootPath();
}
else if(a == goUp)
{
setRootIndex(rootIndex().parent());
m_rootDir = m_fileSystemModel->filePath(rootIndex().parent());
}
else if(a == copy)
{
emit copyFiles(m_fileSystemModel->filePath(index));
}
else if(a == move)
{
emit moveFiles(m_fileSystemModel->filePath(index));
}
else if(a == indexDir)
{
emit indexDirectory(m_fileSystemModel->filePath(index));
}
}
void Filetree::mouseDoubleClickEvent(QMouseEvent *event)
{
QModelIndex index = indexAt(event->pos());
QFileInfo info = m_fileSystemModel->fileInfo(index);
if(info.isFile())
emit fileSelected(info.filePath());
else
QTreeView::mouseDoubleClickEvent(event);
}
+18
View File
@@ -4,6 +4,7 @@
#include <QWidget> #include <QWidget>
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QListView> #include <QListView>
#include <QTreeView>
class FilesystemWidget : public QWidget class FilesystemWidget : public QWidget
{ {
@@ -20,4 +21,21 @@ signals:
void fileSelected(int row); void fileSelected(int row);
}; };
class Filetree : public QTreeView
{
Q_OBJECT
QFileSystemModel *m_fileSystemModel;
QString m_rootDir;
public:
explicit Filetree(QWidget *parent = nullptr);
~Filetree() override;
void contextMenuEvent(QContextMenuEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
signals:
void fileSelected(const QString &path);
void copyFiles(const QString &path);
void moveFiles(const QString &path);
void indexDirectory(const QString &path);
};
#endif // FILESYSTEMWIDGET_H #endif // FILESYSTEMWIDGET_H
+1 -1
View File
@@ -32,7 +32,7 @@ class ImageInfo : public QTreeWidget
Q_OBJECT Q_OBJECT
public: public:
explicit ImageInfo(QWidget *parent); explicit ImageInfo(QWidget *parent);
~ImageInfo(); ~ImageInfo() override;
public slots: public slots:
void setInfo(const ImageInfoData &info); void setInfo(const ImageInfoData &info);
}; };
+8
View File
@@ -257,6 +257,14 @@ int ImageRingList::imageCount() const
return m_images.size(); return m_images.size();
} }
QStringList ImageRingList::imageNames() const
{
QStringList ret;
for(auto &img : m_images)
ret.push_back(img->name());
return ret;
}
QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const
{ {
return createIndex(row, column, m_images.at(row).get()); return createIndex(row, column, m_images.at(row).get());
+2 -1
View File
@@ -59,7 +59,7 @@ class ImageRingList : public QAbstractItemModel
QThreadPool *m_thumbPool; QThreadPool *m_thumbPool;
public: public:
explicit ImageRingList(QObject *parent = 0); explicit ImageRingList(QObject *parent = 0);
~ImageRingList(); ~ImageRingList() override;
bool setDir(const QString path, const QString &currentFile = QString()); bool setDir(const QString path, const QString &currentFile = QString());
void setFile(const QString &file); void setFile(const QString &file);
ImagePtr currentImage(); ImagePtr currentImage();
@@ -74,6 +74,7 @@ public:
void loadThumbnails(); void loadThumbnails();
void stopLoading(); void stopLoading();
int imageCount() const; int imageCount() const;
QStringList imageNames() const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override; QModelIndex parent(const QModelIndex &child) const override;
+6 -6
View File
@@ -21,12 +21,12 @@ public slots:
void bestFit(); void bestFit();
void oneToOne(); void oneToOne();
protected: protected:
void keyPressEvent(QKeyEvent *event); void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event) override;
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event) override;
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event) override;
}; };
#endif // IMAGESCROLLAREA_H #endif // IMAGESCROLLAREA_H
+140 -40
View File
@@ -9,6 +9,8 @@
#include <QMimeData> #include <QMimeData>
#include <QMessageBox> #include <QMessageBox>
#include <QCoreApplication> #include <QCoreApplication>
#include <QPainter>
#include <QFileInfo>
struct RawImageType struct RawImageType
{ {
@@ -44,7 +46,8 @@ void setScrollRange(QScrollBar *scrollBar, int newRange)
scrollBar->setValue(relPos*newRange - page/2); scrollBar->setValue(relPos*newRange - page/2);
} }
ImageWidget::ImageWidget(QWidget *parent) : QOpenGLWidget(parent) ImageWidget::ImageWidget(Database *database, QWidget *parent) : QOpenGLWidget(parent)
, m_database(database)
{ {
setFocusPolicy(Qt::ClickFocus); setFocusPolicy(Qt::ClickFocus);
m_range = UINT16_MAX; m_range = UINT16_MAX;
@@ -58,6 +61,7 @@ ImageWidget::ImageWidget(QWidget *parent) : QOpenGLWidget(parent)
m_imgWidth = m_imgHeight = -1; m_imgWidth = m_imgHeight = -1;
m_superpixel = m_invert = false; m_superpixel = m_invert = false;
m_showThumbnails = false; m_showThumbnails = false;
m_selecting = false;
m_thumbnailCount = 0; m_thumbnailCount = 0;
m_updateTimer = new QTimer(this); m_updateTimer = new QTimer(this);
m_updateTimer->setInterval(500); m_updateTimer->setInterval(500);
@@ -78,12 +82,13 @@ ImageWidget::~ImageWidget()
makeCurrent(); makeCurrent();
} }
void ImageWidget::setImage(const RawImage *image) void ImageWidget::setImage(const RawImage *image, int index)
{ {
if(image == nullptr)return; if(image == nullptr)return;
m_imgWidth = image->width(); m_imgWidth = image->width();
m_imgHeight = image->height(); m_imgHeight = image->height();
m_currentImg = index;
const RawImageType &rawImageType = rawImageTypes[image->type()]; const RawImageType &rawImageType = rawImageTypes[image->type()];
@@ -102,22 +107,6 @@ void ImageWidget::setImage(const RawImage *image)
update(); update();
} }
void ImageWidget::setImage(const QPixmap &pixmap)
{
QImage img = pixmap.toImage();
m_imgWidth = pixmap.width();
m_imgHeight = pixmap.height();
m_image->destroy();
m_image->setData(img);
m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
m_image->setWrapMode(QOpenGLTexture::ClampToBorder);
m_image->setBorderColor(0, 0, 0, 0);
m_bwImg = false;
update();
}
void ImageWidget::setScale(float scale) void ImageWidget::setScale(float scale)
{ {
m_scale = scale; m_scale = scale;
@@ -130,20 +119,29 @@ void ImageWidget::blockRepaint(bool block)
if(!block)update(); if(!block)update();
} }
void ImageWidget::allocateThumbnails(int count) void ImageWidget::allocateThumbnails(const QStringList &paths)
{ {
int count = paths.size();
m_thumbnailCount = count;
m_thumnails.clear();
QStringList marked = m_database->getMarkedFiles();
for(auto &path : paths)
{
QString name = QFileInfo(path).fileName();
m_thumnails.push_back({name, path, QSize(0, 0), marked.contains(path), false});
}
m_thumbnailTexture->destroy(); m_thumbnailTexture->destroy();
m_thumbnailTexture->create(); m_thumbnailTexture->create();
m_thumbnailTexture->setFormat(QOpenGLTexture::RGB16_UNorm); m_thumbnailTexture->setFormat(QOpenGLTexture::RGB16_UNorm);
m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE); m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE);
m_thumbnailTexture->setLayers(count); m_thumbnailTexture->setLayers(paths.size());
m_thumbnailTexture->allocateStorage(); m_thumbnailTexture->allocateStorage();
m_bufferSizes->bind(); m_bufferSizes->bind();
float *tmp = new float[count*3]; float *tmp = new float[count*3];
memset(tmp, 0, count * sizeof(float)*3); memset(tmp, 0, count * sizeof(float)*3);
m_bufferSizes->allocate(tmp, count * sizeof(float)*3); m_bufferSizes->allocate(tmp, count * sizeof(float)*3);
delete [] tmp; delete [] tmp;
m_thumbnailCount = count;
} }
void ImageWidget::setMTFParams(float low, float mid, float high) void ImageWidget::setMTFParams(float low, float mid, float high)
@@ -203,6 +201,7 @@ void ImageWidget::thumbnailLoaded(const Image *image)
int sizes[3] = { std::max(1, a > 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE * a)), std::max(1, a < 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE / a)), image->number() }; int sizes[3] = { std::max(1, a > 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE * a)), std::max(1, a < 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE / a)), image->number() };
m_bufferSizes->bind(); m_bufferSizes->bind();
m_bufferSizes->write(image->number() * sizeof(sizes), sizes, sizeof(sizes)); m_bufferSizes->write(image->number() * sizeof(sizes), sizes, sizeof(sizes));
m_thumnails[image->number()].size = QSize(sizes[0], sizes[1]);
if(!m_updateTimer->isActive())m_updateTimer->start(); if(!m_updateTimer->isActive())m_updateTimer->start();
} }
@@ -222,6 +221,7 @@ void ImageWidget::paintGL()
dx = -width()*0.5f + m_image->width()*m_scale*0.5f; dx = -width()*0.5f + m_image->width()*m_scale*0.5f;
if(height() > m_image->height()*m_scale) if(height() > m_image->height()*m_scale)
dy = -height()*0.5f + m_image->height()*m_scale*0.5f; dy = -height()*0.5f + m_image->height()*m_scale*0.5f;
QBrush highlight = style()->standardPalette().highlight();
if(m_showThumbnails) if(m_showThumbnails)
{ {
@@ -237,6 +237,34 @@ void ImageWidget::paintGL()
mvp.ortho(rect()); mvp.ortho(rect());
m_thumbnailProgram->setUniformValue("mvp", mvp); m_thumbnailProgram->setUniformValue("mvp", mvp);
if(f3)f3->glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, m_thumbnailCount); if(f3)f3->glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, m_thumbnailCount);
QPainter painter(this);
const int w = width()/THUMB_SIZE_BORDER;
const int off = (THUMB_SIZE_BORDER - THUMB_SIZE) / 2;
for(int i=0; i < m_thumbnailCount; i++)
{
float x = (i % w) * THUMB_SIZE_BORDER;
float y = i / w * THUMB_SIZE_BORDER_Y + THUMB_SIZE - m_dy + off;
QRectF rect(x, y, THUMB_SIZE_BORDER, 32);
painter.drawText(rect, Qt::AlignCenter | Qt::TextWrapAnywhere, QString(m_thumnails[i].name));
if(m_thumnails[i].selected)
{
painter.save();
QRectF thumbRect;
painter.setPen(Qt::red);
thumbRect.setSize(m_thumnails[i].size);
thumbRect.moveCenter(QPointF(x + THUMB_SIZE_BORDER / 2, y - THUMB_SIZE / 2));
painter.drawRect(thumbRect);
painter.restore();
}
if(m_currentImg == i)
{
painter.save();
painter.setPen(QPen(highlight, 2.0));
painter.drawRect((i % w) * THUMB_SIZE_BORDER + off, i / w * THUMB_SIZE_BORDER_Y - m_dy + off, THUMB_SIZE, THUMB_SIZE);
painter.restore();
}
}
} }
else else
{ {
@@ -389,12 +417,93 @@ void ImageWidget::dropEvent(QDropEvent *event)
event->ignore(); event->ignore();
} }
ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QWidget(parent) void ImageWidget::mousePressEvent(QMouseEvent *event)
{
if(m_thumbnailCount && event->button() == Qt::LeftButton && event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier))
m_selecting = true;
if(m_selecting)
{
thumbSelect(event);
}
else
event->ignore();
}
void ImageWidget::mouseMoveEvent(QMouseEvent *event)
{
if(m_selecting)
{
thumbSelect(event);
}
else
event->ignore();
}
void ImageWidget::mouseReleaseEvent(QMouseEvent *event)
{
if(m_selecting)
{
m_selecting = false;
event->accept();
QStringList mark;
QStringList unmark;
for(auto &thumb : m_thumnails)
{
if(thumb.dirty)
{
if(thumb.selected)
mark.append(thumb.path);
else
unmark.append(thumb.path);
thumb.dirty = false;
}
}
if(!mark.isEmpty())
m_database->mark(mark);
if(!unmark.isEmpty())
m_database->unmark(unmark);
}
else
event->ignore();
}
void ImageWidget::thumbSelect(QMouseEvent *event)
{
QPoint p = event->pos();
const int off = (THUMB_SIZE_BORDER - THUMB_SIZE) / 2;
p.ry() += m_dy;
const int w = width()/THUMB_SIZE_BORDER;
int x = p.x() / THUMB_SIZE_BORDER;
int y = p.y() / THUMB_SIZE_BORDER_Y;
int i = y * w + x;
event->accept();
QRect rect(x * THUMB_SIZE_BORDER + off, y * THUMB_SIZE_BORDER_Y + off, THUMB_SIZE, THUMB_SIZE);
if(x < w && i < m_thumbnailCount && rect.contains(p, true))
{
bool oldVal = m_thumnails[i].selected;
bool newVal = oldVal;
if(event->modifiers() == Qt::ShiftModifier)
newVal = true;
if(event->modifiers() == Qt::ControlModifier)
newVal = false;
if(newVal != oldVal)
{
m_thumnails[i].selected = newVal;
m_thumnails[i].dirty = true;
update();
}
}
}
ImageScrollAreaGL::ImageScrollAreaGL(Database *database, QWidget *parent) : QWidget(parent)
{ {
QGridLayout *layout = new QGridLayout(this); QGridLayout *layout = new QGridLayout(this);
setLayout(layout); setLayout(layout);
m_imageWidget = new ImageWidget(this); m_imageWidget = new ImageWidget(database, this);
m_verticalScrollBar = new QScrollBar(Qt::Vertical, this); m_verticalScrollBar = new QScrollBar(Qt::Vertical, this);
m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this); m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
@@ -416,24 +525,15 @@ ImageScrollAreaGL::~ImageScrollAreaGL()
} }
void ImageScrollAreaGL::setImage(RawImage *image) void ImageScrollAreaGL::setImage(RawImage *image, int index)
{ {
m_imageWidget->setImage(image); m_imageWidget->setImage(image, index);
m_imgWidth = image->width(); m_imgWidth = image->width();
m_imgHeight = image->height(); m_imgHeight = image->height();
if(m_bestFit)bestFit(); if(m_bestFit)bestFit();
updateScrollbars(); updateScrollbars();
} }
void ImageScrollAreaGL::setImage(const QPixmap &pixmap)
{
m_imageWidget->setImage(pixmap);
m_imgWidth = pixmap.width();
m_imgHeight = pixmap.height();
if(m_bestFit)bestFit();
updateScrollbars();
}
ImageWidget *ImageScrollAreaGL::imageWidget() ImageWidget *ImageScrollAreaGL::imageWidget()
{ {
return m_imageWidget; return m_imageWidget;
@@ -444,8 +544,8 @@ void ImageScrollAreaGL::setThumbnails(int count)
m_thumbCount = count; m_thumbCount = count;
if(m_thumbCount) if(m_thumbCount)
{ {
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER); m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER_Y);
m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER); m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER_Y);
} }
else else
{ {
@@ -461,8 +561,8 @@ void ImageScrollAreaGL::updateScrollbars(bool zoom)
{ {
m_horizontalScrollBar->hide(); m_horizontalScrollBar->hide();
m_verticalScrollBar->show(); m_verticalScrollBar->show();
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER); m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER_Y);
m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER); m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER_Y);
} }
else else
{ {
@@ -484,8 +584,8 @@ void ImageScrollAreaGL::resizeEvent(QResizeEvent *event)
QWidget::resizeEvent(event); QWidget::resizeEvent(event);
if(m_thumbCount) if(m_thumbCount)
{ {
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER); m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER_Y);
m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER); m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER_Y);
} }
else else
{ {
+32 -24
View File
@@ -13,15 +13,16 @@
#include <QTimer> #include <QTimer>
#include "rawimage.h" #include "rawimage.h"
#include "imageringlist.h" #include "imageringlist.h"
#include "database.h"
typedef enum struct ImageThumb
{ {
Linear, QString name;
Log, QString path;
Sqrt, QSize size;
Power, bool selected;
Asinh, bool dirty;
}StretchFunc; };
class ImageWidget : public QOpenGLWidget class ImageWidget : public QOpenGLWidget
{ {
@@ -40,6 +41,7 @@ class ImageWidget : public QOpenGLWidget
std::unique_ptr<QOpenGLTexture> m_thumbnailTexture; std::unique_ptr<QOpenGLTexture> m_thumbnailTexture;
int m_width, m_height; int m_width, m_height;
int m_imgWidth, m_imgHeight; int m_imgWidth, m_imgHeight;
int m_currentImg;
float m_low; float m_low;
float m_mid; float m_mid;
float m_high; float m_high;
@@ -51,15 +53,18 @@ class ImageWidget : public QOpenGLWidget
bool m_invert; bool m_invert;
bool m_superpixel; bool m_superpixel;
bool m_showThumbnails; bool m_showThumbnails;
bool m_selecting;
int m_thumbnailCount; int m_thumbnailCount;
QVector<ImageThumb> m_thumnails;
Database *m_database;
public: public:
explicit ImageWidget(QWidget *parent = nullptr); explicit ImageWidget(Database *database, QWidget *parent = nullptr);
~ImageWidget(); ~ImageWidget() override;
void setImage(const RawImage *image); void setImage(const RawImage *image, int index);
void setImage(const QPixmap &pixmap); void setImage(const QPixmap &pixmap);
void setScale(float scale); void setScale(float scale);
void blockRepaint(bool block); void blockRepaint(bool block);
void allocateThumbnails(int count); void allocateThumbnails(const QStringList &paths);
public slots: public slots:
void setMTFParams(float low, float mid, float high); void setMTFParams(float low, float mid, float high);
void setOffset(int dx, int dy); void setOffset(int dx, int dy);
@@ -69,11 +74,15 @@ public slots:
void thumbnailLoaded(const Image *image); void thumbnailLoaded(const Image *image);
void showThumbnail(bool enable); void showThumbnail(bool enable);
protected: protected:
void paintGL(); void paintGL() override;
void resizeGL(int w, int h); void resizeGL(int w, int h) override;
void initializeGL(); void initializeGL() override;
void dragEnterEvent(QDragEnterEvent *event); void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event); void dropEvent(QDropEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void thumbSelect(QMouseEvent *event);
signals: signals:
void fileDropped(const QString &path); void fileDropped(const QString &path);
}; };
@@ -90,18 +99,17 @@ class ImageScrollAreaGL : public QWidget
bool m_bestFit; bool m_bestFit;
int m_thumbCount; int m_thumbCount;
public: public:
explicit ImageScrollAreaGL(QWidget *parent = nullptr); explicit ImageScrollAreaGL(Database *database, QWidget *parent = nullptr);
~ImageScrollAreaGL(); ~ImageScrollAreaGL() override;
void setImage(RawImage *image); void setImage(RawImage *image, int index);
void setImage(const QPixmap &pixmap);
ImageWidget* imageWidget(); ImageWidget* imageWidget();
void setThumbnails(int count); void setThumbnails(int count);
protected: protected:
void updateScrollbars(bool zoom = false); void updateScrollbars(bool zoom = false);
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event) override;
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event) override;
void zoom(float delta); void zoom(float delta);
public slots: public slots:
void zoomIn(); void zoomIn();
+2 -1
View File
@@ -248,7 +248,8 @@ bool loadFITS(const QString path, ImageInfoData &info, RawImage **image)
} }
} }
noload: noload:
loadFITSHeader(file, info); if(file)
loadFITSHeader(file, info);
fits_close_file(file, &status); fits_close_file(file, &status);
if(status) if(status)
+2 -2
View File
@@ -18,7 +18,7 @@ class LoadRunable : public QRunnable
bool m_thumbnail; bool m_thumbnail;
public: public:
LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail = false); LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail = false);
void run(); void run() override;
}; };
class ConvertRunable : public QRunnable class ConvertRunable : public QRunnable
@@ -27,7 +27,7 @@ class ConvertRunable : public QRunnable
QString m_outfile; QString m_outfile;
public: public:
ConvertRunable(const QString &in, const QString &out); ConvertRunable(const QString &in, const QString &out);
void run(); void run() override;
}; };
#endif // LOADRUNABLE_H #endif // LOADRUNABLE_H
+3
View File
@@ -18,8 +18,11 @@ int main(int argc, char *argv[])
a.setWindowIcon(QIcon(":/org.nou.tenmon.png")); a.setWindowIcon(QIcon(":/org.nou.tenmon.png"));
QTranslator translator; QTranslator translator;
QTranslator translator2;
if(translator.load(QLocale(), "tenmon", "_", ":/translations")) if(translator.load(QLocale(), "tenmon", "_", ":/translations"))
a.installTranslator(&translator); a.installTranslator(&translator);
if(translator2.load(QLocale(), "tenmon", "_", a.applicationDirPath()))
a.installTranslator(&translator2);
MainWindow w; MainWindow w;
w.show(); w.show();
+31 -8
View File
@@ -42,7 +42,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
//setCentralWidget(m_image); //setCentralWidget(m_image);
resize(800, 600); resize(800, 600);
m_imageGL = new ImageScrollAreaGL(this); m_database = new Database(this);
if(!m_database->init())
QMessageBox::critical(this, tr("Can't open DB"), tr("Can't open SQLITE database"));
m_imageGL = new ImageScrollAreaGL(m_database, this);
setCentralWidget(m_imageGL); setCentralWidget(m_imageGL);
m_stretchPanel = new StretchToolbar(this); m_stretchPanel = new StretchToolbar(this);
@@ -55,9 +59,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
m_filesystem = new FilesystemWidget(m_ringList, this); m_filesystem = new FilesystemWidget(m_ringList, this);
connect(m_filesystem, SIGNAL(fileSelected(int)), this, SLOT(loadFile(int))); connect(m_filesystem, SIGNAL(fileSelected(int)), this, SLOT(loadFile(int)));
m_database = new Database(this); m_filetree = new Filetree(this);
if(!m_database->init()) connect(m_filetree, &Filetree::fileSelected, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile));
QMessageBox::critical(this, tr("Can't open DB"), tr("Can't open SQLITE database")); connect(m_filetree, &Filetree::copyFiles, [this](const QString &path){ copyOrMove(true, path); });
connect(m_filetree, &Filetree::moveFiles, [this](const QString &path){ copyOrMove(false, path); });
connect(m_filetree, &Filetree::indexDirectory, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::indexDir));
m_databaseView = new DataBaseView(m_database, this); m_databaseView = new DataBaseView(m_database, this);
connect(m_databaseView, SIGNAL(loadFile(QString)), this, SLOT(loadFile(QString))); connect(m_databaseView, SIGNAL(loadFile(QString)), this, SLOT(loadFile(QString)));
@@ -75,6 +81,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
databaseViewDock->hide(); databaseViewDock->hide();
addDockWidget(Qt::BottomDockWidgetArea, databaseViewDock); addDockWidget(Qt::BottomDockWidgetArea, databaseViewDock);
QDockWidget *filetreeDock = new QDockWidget(tr("File tree"), this);
filetreeDock->setWidget(m_filetree);
filetreeDock->setObjectName("filetreeDock");
databaseViewDock->hide();
addDockWidget(Qt::LeftDockWidgetArea, filetreeDock);
setWindowTitle(tr("Tenmon")); setWindowTitle(tr("Tenmon"));
connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), this, SLOT(pixmapLoaded(Image*))); connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), this, SLOT(pixmapLoaded(Image*)));
@@ -108,7 +120,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
viewMenu->addAction(tr("100%"), m_imageGL, SLOT(oneToOne())); viewMenu->addAction(tr("100%"), m_imageGL, SLOT(oneToOne()));
viewMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), Qt::CTRL + Qt::Key_F11); viewMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), Qt::CTRL + Qt::Key_F11);
QAction *thumbnailsAction = viewMenu->addAction(tr("Thumbnails"), [this](bool checked){ QAction *thumbnailsAction = viewMenu->addAction(tr("Thumbnails"), [this](bool checked){
m_imageGL->imageWidget()->allocateThumbnails(m_ringList->imageCount()); m_imageGL->imageWidget()->allocateThumbnails(m_ringList->imageNames());
m_imageGL->imageWidget()->showThumbnail(checked); m_imageGL->imageWidget()->showThumbnail(checked);
m_imageGL->setThumbnails(checked ? m_ringList->imageCount() : 0); m_imageGL->setThumbnails(checked ? m_ringList->imageCount() : 0);
if(checked)m_ringList->loadThumbnails(); if(checked)m_ringList->loadThumbnails();
@@ -141,7 +153,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
QAction *statsAction = analyzeGroup->addAction(tr("Image statistics")); QAction *statsAction = analyzeGroup->addAction(tr("Image statistics"));
QAction *peakAction = analyzeGroup->addAction(tr("Peak finder")); QAction *peakAction = analyzeGroup->addAction(tr("Peak finder"));
QAction *starAction = analyzeGroup->addAction("Star finder"); QAction *starAction = analyzeGroup->addAction(tr("Star finder"));
statsAction->setCheckable(true); statsAction->setCheckable(true);
peakAction->setCheckable(true); peakAction->setCheckable(true);
starAction->setCheckable(true); starAction->setCheckable(true);
@@ -156,6 +168,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
dockMenu->addAction(m_stretchPanel->toggleViewAction()); dockMenu->addAction(m_stretchPanel->toggleViewAction());
dockMenu->addAction(filesystemDock->toggleViewAction()); dockMenu->addAction(filesystemDock->toggleViewAction());
dockMenu->addAction(databaseViewDock->toggleViewAction()); dockMenu->addAction(databaseViewDock->toggleViewAction());
dockMenu->addAction(filetreeDock->toggleViewAction());
menuBar()->addMenu(dockMenu); menuBar()->addMenu(dockMenu);
QMenu *helpMenu = menuBar()->addMenu(tr("Help")); QMenu *helpMenu = menuBar()->addMenu(tr("Help"));
@@ -259,6 +272,11 @@ void MainWindow::closeEvent(QCloseEvent *event)
void MainWindow::copyOrMove(bool copy) void MainWindow::copyOrMove(bool copy)
{ {
QString dest = QFileDialog::getExistingDirectory(this, tr("Select destination"), _lastDir); QString dest = QFileDialog::getExistingDirectory(this, tr("Select destination"), _lastDir);
copyOrMove(copy, dest);
}
void MainWindow::copyOrMove(bool copy, const QString &dest)
{
QDir dir(dest); QDir dir(dest);
if(!dest.isEmpty() && dir.exists()) if(!dest.isEmpty() && dir.exists())
{ {
@@ -303,8 +321,8 @@ void MainWindow::copyOrMove(bool copy)
#endif #endif
progress.setValue(i++); progress.setValue(i++);
} }
m_database->clearMarkedFiles();
} }
m_database->clearMarkedFiles();
} }
void MainWindow::socketNotify() void MainWindow::socketNotify()
@@ -321,7 +339,7 @@ void MainWindow::pixmapLoaded(Image *image)
//m_image->setImage(image->pixmap()); //m_image->setImage(image->pixmap());
if(image->rawImage()) if(image->rawImage())
{ {
m_imageGL->setImage(image->rawImage()); m_imageGL->setImage(image->rawImage(), image->number());
} }
} }
@@ -356,6 +374,11 @@ void MainWindow::loadFile(int row)
void MainWindow::indexDir() void MainWindow::indexDir()
{ {
QString dir = QFileDialog::getExistingDirectory(this, tr("Index directory"), _lastDir); QString dir = QFileDialog::getExistingDirectory(this, tr("Index directory"), _lastDir);
indexDir(dir);
}
void MainWindow::indexDir(const QString &dir)
{
if(!dir.isEmpty()) if(!dir.isEmpty())
{ {
QProgressDialog progressDialog(tr("Indexing FITS files"), tr("Cancel"), 0, 1, this); QProgressDialog progressDialog(tr("Indexing FITS files"), tr("Cancel"), 0, 1, this);
+7 -4
View File
@@ -22,6 +22,7 @@ class MainWindow : public QMainWindow
Database *m_database; Database *m_database;
ImageInfo *m_info; ImageInfo *m_info;
FilesystemWidget *m_filesystem; FilesystemWidget *m_filesystem;
Filetree *m_filetree;
DataBaseView *m_databaseView; DataBaseView *m_databaseView;
static int socketPair[2]; static int socketPair[2];
QSocketNotifier *socketNotifier; QSocketNotifier *socketNotifier;
@@ -29,14 +30,15 @@ class MainWindow : public QMainWindow
bool _maximized; bool _maximized;
public: public:
MainWindow(QWidget *parent = 0); MainWindow(QWidget *parent = 0);
~MainWindow(); ~MainWindow() override;
protected: protected:
void keyPressEvent(QKeyEvent *event); void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event) override;
void setupSigterm(); void setupSigterm();
static void signalHandler(int); static void signalHandler(int);
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event) override;
void copyOrMove(bool copy); void copyOrMove(bool copy);
void copyOrMove(bool copy, const QString &dest);
protected slots: protected slots:
void socketNotify(); void socketNotify();
void updateWindowTitle(); void updateWindowTitle();
@@ -45,6 +47,7 @@ protected slots:
void loadFile(const QString &path); void loadFile(const QString &path);
void loadFile(int row); void loadFile(int row);
void indexDir(); void indexDir();
void indexDir(const QString &dir);
void reindex(); void reindex();
void saveAs(); void saveAs();
void convert(const QString &outfile); void convert(const QString &outfile);
+1
View File
@@ -11,6 +11,7 @@
const int THUMB_SIZE = 128; const int THUMB_SIZE = 128;
const int THUMB_SIZE_BORDER = 138; const int THUMB_SIZE_BORDER = 138;
const int THUMB_SIZE_BORDER_Y = 158;
class Peak class Peak
{ {
+3 -2
View File
@@ -17,11 +17,12 @@
<file>translations/tenmon_sk.qm</file> <file>translations/tenmon_sk.qm</file>
<file>about/filter.png</file> <file>about/filter.png</file>
<file>about/stretch-panel.png</file> <file>about/stretch-panel.png</file>
<file>translations/tenmon_fr.qm</file>
</qresource> </qresource>
<qresource lang="en" prefix="/"> <qresource prefix="/" lang="en">
<file alias="help">about/help_en</file> <file alias="help">about/help_en</file>
</qresource> </qresource>
<qresource lang="sk" prefix="/"> <qresource prefix="/" lang="sk">
<file alias="help">about/help_sk</file> <file alias="help">about/help_sk</file>
</qresource> </qresource>
<qresource prefix="/help"/> <qresource prefix="/help"/>
+1 -1
View File
@@ -13,7 +13,7 @@ void main(void)
vec2 pos = qt_Vertex * 0.5; vec2 pos = qt_Vertex * 0.5;
pos.y *= -1.0; pos.y *= -1.0;
pos = pos * imageSize_num.xy + 69; pos = pos * imageSize_num.xy + 69;
ivec2 off = ivec2(imageSize_num.z % viewport_row.z, imageSize_num.z / viewport_row.z) * 138; ivec2 off = ivec2(imageSize_num.z % viewport_row.z, imageSize_num.z / viewport_row.z) * ivec2(138, 158);
gl_Position = mvp * vec4(pos - offset + off, 0.0, 1.0); gl_Position = mvp * vec4(pos - offset + off, 0.0, 1.0);
qt_TexCoord0 = vec3(qt_MultiTexCoord0, imageSize_num.z + 0.1); qt_TexCoord0 = vec3(qt_MultiTexCoord0, imageSize_num.z + 0.1);
Binary file not shown.
+39
View File
@@ -30,6 +30,37 @@
<translation>File name</translation> <translation>File name</translation>
</message> </message>
</context> </context>
<context>
<name>Filetree</name>
<message>
<source>Open</source>
<translation>Open</translation>
</message>
<message>
<source>Copy marked files</source>
<translation>Copy marked files</translation>
</message>
<message>
<source>Move marked files</source>
<translation>Move marked files</translation>
</message>
<message>
<source>Index directory</source>
<translation>Index directory</translation>
</message>
<message>
<source>Set as root</source>
<translation>Set as root directory</translation>
</message>
<message>
<source>Reset root</source>
<translation>Reset root directory</translation>
</message>
<message>
<source>Go up</source>
<translation>Go up</translation>
</message>
</context>
<context> <context>
<name>HelpDialog</name> <name>HelpDialog</name>
<message> <message>
@@ -256,6 +287,14 @@
<source>FITS/XISF files database</source> <source>FITS/XISF files database</source>
<translation>FITS/XISF files database</translation> <translation>FITS/XISF files database</translation>
</message> </message>
<message>
<source>File tree</source>
<translation>File tree</translation>
</message>
<message>
<source>Star finder</source>
<translation>Star finder</translation>
</message>
</context> </context>
<context> <context>
<name>MarkedFiles</name> <name>MarkedFiles</name>
Binary file not shown.
+423
View File
@@ -0,0 +1,423 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="fr_FR" sourcelanguage="en">
<context>
<name>About</name>
<message>
<source>About Tenmon</source>
<translation>A propos de Tenmon</translation>
</message>
</context>
<context>
<name>DataBaseView</name>
<message>
<source>Select columns</source>
<translation>Choix des colonnes</translation>
</message>
<message>
<source>Text to search, you can % as wildcard</source>
<translation>Texte à chercher, utilisez % comme caractère générique</translation>
</message>
<message>
<source>Filter</source>
<translation>Filtre</translation>
</message>
</context>
<context>
<name>FITSFileModel</name>
<message>
<source>File name</source>
<translation>Nom de fichier</translation>
</message>
</context>
<context>
<name>Filetree</name>
<message>
<source>Open</source>
<translation type="unfinished">Ouvrir</translation>
</message>
<message>
<source>Copy marked files</source>
<translation type="unfinished">Copier les fichiers marqués</translation>
</message>
<message>
<source>Move marked files</source>
<translation type="unfinished">Déplace les fichiers marqués</translation>
</message>
<message>
<source>Index directory</source>
<translation type="unfinished">Indexation du répertoire</translation>
</message>
<message>
<source>Set as root</source>
<translation type="unfinished">Définir comme répertoire racine</translation>
</message>
<message>
<source>Reset root</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Go up</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>HelpDialog</name>
<message>
<source>Help</source>
<translation>Aide</translation>
</message>
</context>
<context>
<name>ImageInfo</name>
<message>
<source>Property</source>
<translation>Propriété</translation>
</message>
<message>
<source>Value</source>
<translation>Valeur</translation>
</message>
<message>
<source>Comment</source>
<translation>Commentaire</translation>
</message>
<message>
<source>FITS Header</source>
<translation>En-tête FITS</translation>
</message>
<message>
<source>Image info</source>
<translation>Informations sur l&apos;image</translation>
</message>
</context>
<context>
<name>ImageRingList</name>
<message>
<source>Name</source>
<translation>Nom</translation>
</message>
</context>
<context>
<name>ImageWidget</name>
<message>
<source>OpenGL error</source>
<translation>Erreur OpenGL</translation>
</message>
<message>
<source>Could not initialize OpenGL 3.3 context. Ensure that proper GPU driver is installed.</source>
<translation>Impossible d&apos;initialiser le contexte OpenGL 3.3. Assurez-vous que le pilote GPU approprié est installé.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<source>Image info</source>
<translation>Information de l&apos;image</translation>
</message>
<message>
<source>Can&apos;t open DB</source>
<translation>Ne peut ouvrir la base de donnée</translation>
</message>
<message>
<source>Can&apos;t open SQLITE database</source>
<translation>Ne peut ouvrir la base de donnée SQLITE</translation>
</message>
<message>
<source>Filesystem</source>
<translation>Système de fichier</translation>
</message>
<message>
<source>FITS files database</source>
<translation type="vanished">FITS files database</translation>
</message>
<message>
<source>Tenmon</source>
<translation>Tenmon</translation>
</message>
<message>
<source>File</source>
<translation>Fichier</translation>
</message>
<message>
<source>Open</source>
<translation>Ouvrir</translation>
</message>
<message>
<source>Copy marked files</source>
<translation>Copier les fichiers marqués</translation>
</message>
<message>
<source>Save as</source>
<translation>Enregistrer sous</translation>
</message>
<message>
<source>Live mode</source>
<translation>Mode temps réel</translation>
</message>
<message>
<source>Exit</source>
<translation>Sortir</translation>
</message>
<message>
<source>View</source>
<translation>Voir</translation>
</message>
<message>
<source>Zoom In</source>
<translation>Zoom avant</translation>
</message>
<message>
<source>Zoom Out</source>
<translation>Zoom arrière</translation>
</message>
<message>
<source>Best Fit</source>
<translation>Meilleur ajustement</translation>
</message>
<message>
<source>100%</source>
<translation>100%</translation>
</message>
<message>
<source>Fullscreen</source>
<translation>Plein écran</translation>
</message>
<message>
<source>Select</source>
<translation>Choisir</translation>
</message>
<message>
<source>Mark</source>
<translation>Marquer</translation>
</message>
<message>
<source>Unmark</source>
<translation>Décocher</translation>
</message>
<message>
<source>Mark and next</source>
<translation>Marquer et suivant</translation>
</message>
<message>
<source>Unmark and next</source>
<translation>Décocher et suivant</translation>
</message>
<message>
<source>Analyze</source>
<translation>Analyse</translation>
</message>
<message>
<source>Image statistics</source>
<translation>Statistiques de l&apos;image</translation>
</message>
<message>
<source>Peak finder</source>
<translation>Détecteur de pic</translation>
</message>
<message>
<source>Docks</source>
<translation>Encrage</translation>
</message>
<message>
<source>Open file</source>
<translation>Ouvrir le ficher</translation>
</message>
<message>
<source>Select destination</source>
<translation>Choisir la destination</translation>
</message>
<message>
<source>Copying</source>
<translation>Copier</translation>
</message>
<message>
<source>Cancel</source>
<translation>Abandon</translation>
</message>
<message>
<source>Move marked files</source>
<translation>Déplace les fichiers marqués</translation>
</message>
<message>
<source>Index directory</source>
<translation>Indexation du répertoire</translation>
</message>
<message>
<source>Thumbnails</source>
<translation>Vignettes</translation>
</message>
<message>
<source>Show marked</source>
<translation>Afficher marqué</translation>
</message>
<message>
<source>Help</source>
<translation>Aide</translation>
</message>
<message>
<source>About Tenmon</source>
<translation>A propos de Tenmon</translation>
</message>
<message>
<source>About Qt</source>
<translation>A propos de Qt</translation>
</message>
<message>
<source>Moving</source>
<translation>Déplacement</translation>
</message>
<message>
<source>Images (*.jpg *.jpeg *.png *.cr2 *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.FIT *.FITS *.XISF)</source>
<translation>Images (*.jpg *.jpeg *.png *.cr2 *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.FIT *.FITS *.XISF)</translation>
</message>
<message>
<source>Indexing FITS files</source>
<translation>Indexation des fichiers FITS</translation>
</message>
<message>
<source>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</source>
<translation>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</translation>
</message>
<message>
<source>Reindex files</source>
<translation>-indexer les fichiers</translation>
</message>
<message>
<source>FITS/XISF files database</source>
<translation>Base de donnée FITS/XISF</translation>
</message>
<message>
<source>File tree</source>
<translation>Arborescence de fichiers</translation>
</message>
<message>
<source>Star finder</source>
<translation>Chercheur d&apos;étoiles</translation>
</message>
</context>
<context>
<name>MarkedFiles</name>
<message>
<source>Marked files</source>
<translation>Fichiers marqués</translation>
</message>
<message>
<source>Filename</source>
<translation>Nom de fichier</translation>
</message>
<message>
<source>Clear selected</source>
<translation>Effacer la sélection</translation>
</message>
<message>
<source>Clear all</source>
<translation>Effacer tout</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<source>ISO</source>
<translation>ISO</translation>
</message>
<message>
<source>Shutter speed</source>
<translation>Vitesse d&apos;obturation</translation>
</message>
<message>
<source>Width</source>
<translation>Largeur</translation>
</message>
<message>
<source>Height</source>
<translation>Hauteur</translation>
</message>
<message>
<source>Error</source>
<translation>Erreur</translation>
</message>
<message>
<source>Filename</source>
<translation>Nom de fichier</translation>
</message>
<message>
<source>Mean</source>
<translation>Moyenne</translation>
</message>
<message>
<source>Standart deviation</source>
<translation>Écart-type</translation>
</message>
<message>
<source>Median</source>
<translation>Médiane</translation>
</message>
<message>
<source>Minimum</source>
<translation>Minimum</translation>
</message>
<message>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
<message>
<source>MAD</source>
<translation>MAD</translation>
</message>
<message>
<source>Peaks</source>
<translation>Pics</translation>
</message>
<message>
<source>Peaks draw</source>
<translation>Dessin des pic</translation>
</message>
<message>
<source>FWHM X</source>
<translation>FWHM X</translation>
</message>
<message>
<source>FWHM Y</source>
<translation>FWHM Y</translation>
</message>
<message>
<source>Unsupported sample format</source>
<translation>Format non pris en charge</translation>
</message>
</context>
<context>
<name>SelectColumnsDialog</name>
<message>
<source>Select columns</source>
<translation>Choix des colonnes</translation>
</message>
</context>
<context>
<name>StretchToolbar</name>
<message>
<source>Stretch toolbar</source>
<translation>Barre d&apos;outils étirer</translation>
</message>
<message>
<source>Auto Stretch F12</source>
<translation>Étirement automatique F12</translation>
</message>
<message>
<source>Reset Screen Transfer Function F11</source>
<translation>Réinitialiser la fonction de transfert d&apos;écran F11</translation>
</message>
<message>
<source>Invert colors</source>
<translation>Inverser les couleurs</translation>
</message>
<message>
<source>Superpixel CFA draw 2x2 pixel as one</source>
<translation>Superpixel CFA dessine 2x2 pixels comme un seul</translation>
</message>
<message>
<source>Apply auto stretch on load</source>
<translation>Appliquer l&apos;étirement automatiquement au chargement</translation>
</message>
</context>
</TS>
Binary file not shown.
+39
View File
@@ -31,6 +31,37 @@
<translation>Meno súboru</translation> <translation>Meno súboru</translation>
</message> </message>
</context> </context>
<context>
<name>Filetree</name>
<message>
<source>Open</source>
<translation>Otvoriť</translation>
</message>
<message>
<source>Copy marked files</source>
<translation>Skopírovať označené súbory</translation>
</message>
<message>
<source>Move marked files</source>
<translation>Presunúť označené súbory</translation>
</message>
<message>
<source>Index directory</source>
<translation>Indexovať adresár</translation>
</message>
<message>
<source>Set as root</source>
<translation>Nastav koreňový adresár</translation>
</message>
<message>
<source>Reset root</source>
<translation>Resetuj koreňový adresár</translation>
</message>
<message>
<source>Go up</source>
<translation>O úroveň vyššie</translation>
</message>
</context>
<context> <context>
<name>HelpDialog</name> <name>HelpDialog</name>
<message> <message>
@@ -269,6 +300,14 @@
<source>FITS/XISF files database</source> <source>FITS/XISF files database</source>
<translation>Databáza FITS/XISF súborov</translation> <translation>Databáza FITS/XISF súborov</translation>
</message> </message>
<message>
<source>File tree</source>
<translation>Strom súborov</translation>
</message>
<message>
<source>Star finder</source>
<translation>Vyhľadávač hviezd</translation>
</message>
</context> </context>
<context> <context>
<name>MarkedFiles</name> <name>MarkedFiles</name>