Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a4cfc65d4b | |||
| b4746be190 | |||
| 9ceb7556f9 | |||
| 41b29f0701 | |||
| 67ae2d4b62 | |||
| b6b6863331 | |||
| 571fa57af2 | |||
| abb3d631bf | |||
| b65911943e | |||
| 9d9f8db499 | |||
| 3060b17c0c | |||
| fcf336d63a | |||
| 54ef8e990c | |||
| 94466a6b9b | |||
| b84d8127ad | |||
| c971a919ec | |||
| 8c248b7cfc | |||
| 43b510a78c |
@@ -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.
|
||||
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>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -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
|
||||
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>
|
||||
<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>
|
||||
<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á
|
||||
|
||||
@@ -76,6 +76,20 @@ bool Database::unmark(const QString &filename)
|
||||
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)
|
||||
{
|
||||
m_isMarkedQuery.bindValue(":name", filename);
|
||||
@@ -143,6 +157,7 @@ void Database::reindex(QProgressDialog *progress)
|
||||
{
|
||||
QVariantList deleteids;
|
||||
QSqlDatabase database = QSqlDatabase::database();
|
||||
database.transaction();
|
||||
QSqlQuery files = database.exec("SELECT id,file,mtime FROM fits_files");
|
||||
progress->setMaximum(files.size());
|
||||
int i = 0;
|
||||
@@ -155,10 +170,16 @@ void Database::reindex(QProgressDialog *progress)
|
||||
if(!file.exists())
|
||||
deleteids.append(files.value(0));
|
||||
progress->setValue(i++);
|
||||
if(progress->wasCanceled())
|
||||
{
|
||||
database.rollback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QSqlQuery deleteFiles("DELETE FROM fits_files WHERE id = ?", database);
|
||||
deleteFiles.bindValue(0, deleteids);
|
||||
deleteFiles.execBatch();
|
||||
database.commit();
|
||||
}
|
||||
|
||||
QStringList Database::getFitsKeywords()
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
bool init();
|
||||
bool mark(const QString &filename);
|
||||
bool unmark(const QString &filename);
|
||||
bool mark(const QStringList &filenames);
|
||||
bool unmark(const QStringList &filenames);
|
||||
bool isMarked(const QString &filename);
|
||||
QStringList getMarkedFiles();
|
||||
void clearMarkedFiles();
|
||||
|
||||
+85
-5
@@ -6,6 +6,8 @@
|
||||
#include <QHeaderView>
|
||||
#include <QSqlError>
|
||||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
#include <iostream>
|
||||
|
||||
const QStringList DEFAULT_COLUMNS = {"EXPTIME", "OBJECT", "RA", "DEC"};
|
||||
@@ -47,9 +49,9 @@ QStringList SelectColumnsDialog::selectedColumns()
|
||||
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)
|
||||
@@ -86,6 +88,44 @@ void FITSFileModel::setFilter(const QStringList &key, const QStringList &value)
|
||||
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()
|
||||
{
|
||||
QString cols;
|
||||
@@ -122,6 +162,31 @@ void FITSFileModel::prepareQuery()
|
||||
std::cout << sql.toStdString() << std::endl;
|
||||
if(lastError().type() != QSqlError::NoError)
|
||||
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)
|
||||
@@ -130,14 +195,15 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
m_tableView = new QTableView(this);
|
||||
m_tableView = new DatabaseTableView(this);
|
||||
m_tableView->verticalHeader()->setDefaultSectionSize(1);
|
||||
m_tableView->setSortingEnabled(true);
|
||||
m_tableView->horizontalHeader()->setSortIndicatorShown(true);
|
||||
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
layout->addWidget(m_tableView);
|
||||
connect(m_tableView, &QTableView::activated, this, &DataBaseView::itemActivated);
|
||||
|
||||
m_model = new FITSFileModel(this);
|
||||
m_model = new FITSFileModel(m_database, this);
|
||||
|
||||
QSettings settings;
|
||||
m_tableView->setModel(m_model);
|
||||
@@ -151,6 +217,21 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
|
||||
hlayout->addWidget(selectColumnsButton);
|
||||
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++)
|
||||
{
|
||||
m_filterKeyword[i] = new QComboBox(this);
|
||||
@@ -214,4 +295,3 @@ void DataBaseView::applyFilter()
|
||||
}
|
||||
m_model->setFilter(keys, values);
|
||||
}
|
||||
|
||||
|
||||
+22
-5
@@ -15,7 +15,7 @@ class SelectColumnsDialog : public QDialog
|
||||
Q_OBJECT
|
||||
QListWidget *m_listWidget;
|
||||
public:
|
||||
SelectColumnsDialog(QWidget *parent = nullptr);
|
||||
explicit SelectColumnsDialog(QWidget *parent = nullptr);
|
||||
void setColumns(QStringList columns);
|
||||
QStringList selectedColumns();
|
||||
};
|
||||
@@ -27,26 +27,43 @@ class FITSFileModel : public QSqlQueryModel
|
||||
QString m_sort;
|
||||
QStringList m_key;
|
||||
QStringList m_value;
|
||||
QSet<QString> m_markedFiles;
|
||||
Database *m_database;
|
||||
public:
|
||||
FITSFileModel(QObject *parent = nullptr);
|
||||
void sort(int column, Qt::SortOrder order);
|
||||
explicit FITSFileModel(Database *database, QObject *parent = nullptr);
|
||||
void sort(int column, Qt::SortOrder order) override;
|
||||
void setColumns(const QStringList &columns);
|
||||
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:
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
Database *m_database;
|
||||
QTableView *m_tableView;
|
||||
DatabaseTableView *m_tableView;
|
||||
FITSFileModel *m_model;
|
||||
QComboBox *m_filterKeyword[3];
|
||||
QLineEdit *m_search[3];
|
||||
public:
|
||||
explicit DataBaseView(Database *database, QWidget *parent = nullptr);
|
||||
~DataBaseView();
|
||||
~DataBaseView() override;
|
||||
public slots:
|
||||
void selectColumns();
|
||||
void loadDatabase();
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#include "filesystemwidget.h"
|
||||
#include <QSettings>
|
||||
#include <QVBoxLayout>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QMenu>
|
||||
#include <QSettings>
|
||||
#include <QHeaderView>
|
||||
|
||||
FilesystemWidget::FilesystemWidget(QAbstractItemModel *model, QWidget *parent) : QWidget(parent)
|
||||
, m_model(model)
|
||||
@@ -34,3 +38,97 @@ void FilesystemWidget::fileClicked(const QModelIndex &index)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <QWidget>
|
||||
#include <QFileSystemModel>
|
||||
#include <QListView>
|
||||
#include <QTreeView>
|
||||
|
||||
class FilesystemWidget : public QWidget
|
||||
{
|
||||
@@ -20,4 +21,21 @@ signals:
|
||||
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
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ class ImageInfo : public QTreeWidget
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImageInfo(QWidget *parent);
|
||||
~ImageInfo();
|
||||
~ImageInfo() override;
|
||||
public slots:
|
||||
void setInfo(const ImageInfoData &info);
|
||||
};
|
||||
|
||||
@@ -257,6 +257,14 @@ int ImageRingList::imageCount() const
|
||||
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
|
||||
{
|
||||
return createIndex(row, column, m_images.at(row).get());
|
||||
|
||||
+2
-1
@@ -59,7 +59,7 @@ class ImageRingList : public QAbstractItemModel
|
||||
QThreadPool *m_thumbPool;
|
||||
public:
|
||||
explicit ImageRingList(QObject *parent = 0);
|
||||
~ImageRingList();
|
||||
~ImageRingList() override;
|
||||
bool setDir(const QString path, const QString ¤tFile = QString());
|
||||
void setFile(const QString &file);
|
||||
ImagePtr currentImage();
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
void loadThumbnails();
|
||||
void stopLoading();
|
||||
int imageCount() const;
|
||||
QStringList imageNames() const;
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
|
||||
+6
-6
@@ -21,12 +21,12 @@ public slots:
|
||||
void bestFit();
|
||||
void oneToOne();
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
void keyReleaseEvent(QKeyEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void keyReleaseEvent(QKeyEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // IMAGESCROLLAREA_H
|
||||
|
||||
+140
-40
@@ -9,6 +9,8 @@
|
||||
#include <QMimeData>
|
||||
#include <QMessageBox>
|
||||
#include <QCoreApplication>
|
||||
#include <QPainter>
|
||||
#include <QFileInfo>
|
||||
|
||||
struct RawImageType
|
||||
{
|
||||
@@ -44,7 +46,8 @@ void setScrollRange(QScrollBar *scrollBar, int newRange)
|
||||
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);
|
||||
m_range = UINT16_MAX;
|
||||
@@ -58,6 +61,7 @@ ImageWidget::ImageWidget(QWidget *parent) : QOpenGLWidget(parent)
|
||||
m_imgWidth = m_imgHeight = -1;
|
||||
m_superpixel = m_invert = false;
|
||||
m_showThumbnails = false;
|
||||
m_selecting = false;
|
||||
m_thumbnailCount = 0;
|
||||
m_updateTimer = new QTimer(this);
|
||||
m_updateTimer->setInterval(500);
|
||||
@@ -78,12 +82,13 @@ ImageWidget::~ImageWidget()
|
||||
makeCurrent();
|
||||
}
|
||||
|
||||
void ImageWidget::setImage(const RawImage *image)
|
||||
void ImageWidget::setImage(const RawImage *image, int index)
|
||||
{
|
||||
if(image == nullptr)return;
|
||||
|
||||
m_imgWidth = image->width();
|
||||
m_imgHeight = image->height();
|
||||
m_currentImg = index;
|
||||
|
||||
const RawImageType &rawImageType = rawImageTypes[image->type()];
|
||||
|
||||
@@ -102,22 +107,6 @@ void ImageWidget::setImage(const RawImage *image)
|
||||
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)
|
||||
{
|
||||
m_scale = scale;
|
||||
@@ -130,20 +119,29 @@ void ImageWidget::blockRepaint(bool block)
|
||||
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->create();
|
||||
m_thumbnailTexture->setFormat(QOpenGLTexture::RGB16_UNorm);
|
||||
m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE);
|
||||
m_thumbnailTexture->setLayers(count);
|
||||
m_thumbnailTexture->setLayers(paths.size());
|
||||
m_thumbnailTexture->allocateStorage();
|
||||
m_bufferSizes->bind();
|
||||
float *tmp = new float[count*3];
|
||||
memset(tmp, 0, count * sizeof(float)*3);
|
||||
m_bufferSizes->allocate(tmp, count * sizeof(float)*3);
|
||||
delete [] tmp;
|
||||
m_thumbnailCount = count;
|
||||
}
|
||||
|
||||
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() };
|
||||
m_bufferSizes->bind();
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -222,6 +221,7 @@ void ImageWidget::paintGL()
|
||||
dx = -width()*0.5f + m_image->width()*m_scale*0.5f;
|
||||
if(height() > m_image->height()*m_scale)
|
||||
dy = -height()*0.5f + m_image->height()*m_scale*0.5f;
|
||||
QBrush highlight = style()->standardPalette().highlight();
|
||||
|
||||
if(m_showThumbnails)
|
||||
{
|
||||
@@ -237,6 +237,34 @@ void ImageWidget::paintGL()
|
||||
mvp.ortho(rect());
|
||||
m_thumbnailProgram->setUniformValue("mvp", mvp);
|
||||
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
|
||||
{
|
||||
@@ -389,12 +417,93 @@ void ImageWidget::dropEvent(QDropEvent *event)
|
||||
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);
|
||||
setLayout(layout);
|
||||
|
||||
m_imageWidget = new ImageWidget(this);
|
||||
m_imageWidget = new ImageWidget(database, this);
|
||||
|
||||
m_verticalScrollBar = new QScrollBar(Qt::Vertical, 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_imgHeight = image->height();
|
||||
if(m_bestFit)bestFit();
|
||||
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()
|
||||
{
|
||||
return m_imageWidget;
|
||||
@@ -444,8 +544,8 @@ void ImageScrollAreaGL::setThumbnails(int count)
|
||||
m_thumbCount = count;
|
||||
if(m_thumbCount)
|
||||
{
|
||||
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER);
|
||||
m_verticalScrollBar->setPageStep(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_Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -461,8 +561,8 @@ void ImageScrollAreaGL::updateScrollbars(bool zoom)
|
||||
{
|
||||
m_horizontalScrollBar->hide();
|
||||
m_verticalScrollBar->show();
|
||||
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER);
|
||||
m_verticalScrollBar->setPageStep(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_Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -484,8 +584,8 @@ void ImageScrollAreaGL::resizeEvent(QResizeEvent *event)
|
||||
QWidget::resizeEvent(event);
|
||||
if(m_thumbCount)
|
||||
{
|
||||
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER);
|
||||
m_verticalScrollBar->setPageStep(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_Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+32
-24
@@ -13,15 +13,16 @@
|
||||
#include <QTimer>
|
||||
#include "rawimage.h"
|
||||
#include "imageringlist.h"
|
||||
#include "database.h"
|
||||
|
||||
typedef enum
|
||||
struct ImageThumb
|
||||
{
|
||||
Linear,
|
||||
Log,
|
||||
Sqrt,
|
||||
Power,
|
||||
Asinh,
|
||||
}StretchFunc;
|
||||
QString name;
|
||||
QString path;
|
||||
QSize size;
|
||||
bool selected;
|
||||
bool dirty;
|
||||
};
|
||||
|
||||
class ImageWidget : public QOpenGLWidget
|
||||
{
|
||||
@@ -40,6 +41,7 @@ class ImageWidget : public QOpenGLWidget
|
||||
std::unique_ptr<QOpenGLTexture> m_thumbnailTexture;
|
||||
int m_width, m_height;
|
||||
int m_imgWidth, m_imgHeight;
|
||||
int m_currentImg;
|
||||
float m_low;
|
||||
float m_mid;
|
||||
float m_high;
|
||||
@@ -51,15 +53,18 @@ class ImageWidget : public QOpenGLWidget
|
||||
bool m_invert;
|
||||
bool m_superpixel;
|
||||
bool m_showThumbnails;
|
||||
bool m_selecting;
|
||||
int m_thumbnailCount;
|
||||
QVector<ImageThumb> m_thumnails;
|
||||
Database *m_database;
|
||||
public:
|
||||
explicit ImageWidget(QWidget *parent = nullptr);
|
||||
~ImageWidget();
|
||||
void setImage(const RawImage *image);
|
||||
explicit ImageWidget(Database *database, QWidget *parent = nullptr);
|
||||
~ImageWidget() override;
|
||||
void setImage(const RawImage *image, int index);
|
||||
void setImage(const QPixmap &pixmap);
|
||||
void setScale(float scale);
|
||||
void blockRepaint(bool block);
|
||||
void allocateThumbnails(int count);
|
||||
void allocateThumbnails(const QStringList &paths);
|
||||
public slots:
|
||||
void setMTFParams(float low, float mid, float high);
|
||||
void setOffset(int dx, int dy);
|
||||
@@ -69,11 +74,15 @@ public slots:
|
||||
void thumbnailLoaded(const Image *image);
|
||||
void showThumbnail(bool enable);
|
||||
protected:
|
||||
void paintGL();
|
||||
void resizeGL(int w, int h);
|
||||
void initializeGL();
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
void paintGL() override;
|
||||
void resizeGL(int w, int h) override;
|
||||
void initializeGL() override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
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:
|
||||
void fileDropped(const QString &path);
|
||||
};
|
||||
@@ -90,18 +99,17 @@ class ImageScrollAreaGL : public QWidget
|
||||
bool m_bestFit;
|
||||
int m_thumbCount;
|
||||
public:
|
||||
explicit ImageScrollAreaGL(QWidget *parent = nullptr);
|
||||
~ImageScrollAreaGL();
|
||||
void setImage(RawImage *image);
|
||||
void setImage(const QPixmap &pixmap);
|
||||
explicit ImageScrollAreaGL(Database *database, QWidget *parent = nullptr);
|
||||
~ImageScrollAreaGL() override;
|
||||
void setImage(RawImage *image, int index);
|
||||
ImageWidget* imageWidget();
|
||||
void setThumbnails(int count);
|
||||
protected:
|
||||
void updateScrollbars(bool zoom = false);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
void zoom(float delta);
|
||||
public slots:
|
||||
void zoomIn();
|
||||
|
||||
+2
-1
@@ -248,7 +248,8 @@ bool loadFITS(const QString path, ImageInfoData &info, RawImage **image)
|
||||
}
|
||||
}
|
||||
noload:
|
||||
loadFITSHeader(file, info);
|
||||
if(file)
|
||||
loadFITSHeader(file, info);
|
||||
|
||||
fits_close_file(file, &status);
|
||||
if(status)
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ class LoadRunable : public QRunnable
|
||||
bool m_thumbnail;
|
||||
public:
|
||||
LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail = false);
|
||||
void run();
|
||||
void run() override;
|
||||
};
|
||||
|
||||
class ConvertRunable : public QRunnable
|
||||
@@ -27,7 +27,7 @@ class ConvertRunable : public QRunnable
|
||||
QString m_outfile;
|
||||
public:
|
||||
ConvertRunable(const QString &in, const QString &out);
|
||||
void run();
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif // LOADRUNABLE_H
|
||||
|
||||
@@ -18,8 +18,11 @@ int main(int argc, char *argv[])
|
||||
a.setWindowIcon(QIcon(":/org.nou.tenmon.png"));
|
||||
|
||||
QTranslator translator;
|
||||
QTranslator translator2;
|
||||
if(translator.load(QLocale(), "tenmon", "_", ":/translations"))
|
||||
a.installTranslator(&translator);
|
||||
if(translator2.load(QLocale(), "tenmon", "_", a.applicationDirPath()))
|
||||
a.installTranslator(&translator2);
|
||||
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
+31
-8
@@ -42,7 +42,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
//setCentralWidget(m_image);
|
||||
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);
|
||||
|
||||
m_stretchPanel = new StretchToolbar(this);
|
||||
@@ -55,9 +59,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
m_filesystem = new FilesystemWidget(m_ringList, this);
|
||||
connect(m_filesystem, SIGNAL(fileSelected(int)), this, SLOT(loadFile(int)));
|
||||
|
||||
m_database = new Database(this);
|
||||
if(!m_database->init())
|
||||
QMessageBox::critical(this, tr("Can't open DB"), tr("Can't open SQLITE database"));
|
||||
m_filetree = new Filetree(this);
|
||||
connect(m_filetree, &Filetree::fileSelected, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile));
|
||||
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);
|
||||
connect(m_databaseView, SIGNAL(loadFile(QString)), this, SLOT(loadFile(QString)));
|
||||
@@ -75,6 +81,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
databaseViewDock->hide();
|
||||
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"));
|
||||
|
||||
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("Fullscreen"), this, SLOT(toggleFullScreen()), Qt::CTRL + Qt::Key_F11);
|
||||
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->setThumbnails(checked ? m_ringList->imageCount() : 0);
|
||||
if(checked)m_ringList->loadThumbnails();
|
||||
@@ -141,7 +153,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
|
||||
QAction *statsAction = analyzeGroup->addAction(tr("Image statistics"));
|
||||
QAction *peakAction = analyzeGroup->addAction(tr("Peak finder"));
|
||||
QAction *starAction = analyzeGroup->addAction("Star finder");
|
||||
QAction *starAction = analyzeGroup->addAction(tr("Star finder"));
|
||||
statsAction->setCheckable(true);
|
||||
peakAction->setCheckable(true);
|
||||
starAction->setCheckable(true);
|
||||
@@ -156,6 +168,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
dockMenu->addAction(m_stretchPanel->toggleViewAction());
|
||||
dockMenu->addAction(filesystemDock->toggleViewAction());
|
||||
dockMenu->addAction(databaseViewDock->toggleViewAction());
|
||||
dockMenu->addAction(filetreeDock->toggleViewAction());
|
||||
menuBar()->addMenu(dockMenu);
|
||||
|
||||
QMenu *helpMenu = menuBar()->addMenu(tr("Help"));
|
||||
@@ -259,6 +272,11 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
||||
void MainWindow::copyOrMove(bool copy)
|
||||
{
|
||||
QString dest = QFileDialog::getExistingDirectory(this, tr("Select destination"), _lastDir);
|
||||
copyOrMove(copy, dest);
|
||||
}
|
||||
|
||||
void MainWindow::copyOrMove(bool copy, const QString &dest)
|
||||
{
|
||||
QDir dir(dest);
|
||||
if(!dest.isEmpty() && dir.exists())
|
||||
{
|
||||
@@ -303,8 +321,8 @@ void MainWindow::copyOrMove(bool copy)
|
||||
#endif
|
||||
progress.setValue(i++);
|
||||
}
|
||||
m_database->clearMarkedFiles();
|
||||
}
|
||||
m_database->clearMarkedFiles();
|
||||
}
|
||||
|
||||
void MainWindow::socketNotify()
|
||||
@@ -321,7 +339,7 @@ void MainWindow::pixmapLoaded(Image *image)
|
||||
//m_image->setImage(image->pixmap());
|
||||
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()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory(this, tr("Index directory"), _lastDir);
|
||||
indexDir(dir);
|
||||
}
|
||||
|
||||
void MainWindow::indexDir(const QString &dir)
|
||||
{
|
||||
if(!dir.isEmpty())
|
||||
{
|
||||
QProgressDialog progressDialog(tr("Indexing FITS files"), tr("Cancel"), 0, 1, this);
|
||||
|
||||
+7
-4
@@ -22,6 +22,7 @@ class MainWindow : public QMainWindow
|
||||
Database *m_database;
|
||||
ImageInfo *m_info;
|
||||
FilesystemWidget *m_filesystem;
|
||||
Filetree *m_filetree;
|
||||
DataBaseView *m_databaseView;
|
||||
static int socketPair[2];
|
||||
QSocketNotifier *socketNotifier;
|
||||
@@ -29,14 +30,15 @@ class MainWindow : public QMainWindow
|
||||
bool _maximized;
|
||||
public:
|
||||
MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
~MainWindow() override;
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
void keyReleaseEvent(QKeyEvent *event);
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void keyReleaseEvent(QKeyEvent *event) override;
|
||||
void setupSigterm();
|
||||
static void signalHandler(int);
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void copyOrMove(bool copy);
|
||||
void copyOrMove(bool copy, const QString &dest);
|
||||
protected slots:
|
||||
void socketNotify();
|
||||
void updateWindowTitle();
|
||||
@@ -45,6 +47,7 @@ protected slots:
|
||||
void loadFile(const QString &path);
|
||||
void loadFile(int row);
|
||||
void indexDir();
|
||||
void indexDir(const QString &dir);
|
||||
void reindex();
|
||||
void saveAs();
|
||||
void convert(const QString &outfile);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
const int THUMB_SIZE = 128;
|
||||
const int THUMB_SIZE_BORDER = 138;
|
||||
const int THUMB_SIZE_BORDER_Y = 158;
|
||||
|
||||
class Peak
|
||||
{
|
||||
|
||||
+3
-2
@@ -17,11 +17,12 @@
|
||||
<file>translations/tenmon_sk.qm</file>
|
||||
<file>about/filter.png</file>
|
||||
<file>about/stretch-panel.png</file>
|
||||
<file>translations/tenmon_fr.qm</file>
|
||||
</qresource>
|
||||
<qresource lang="en" prefix="/">
|
||||
<qresource prefix="/" lang="en">
|
||||
<file alias="help">about/help_en</file>
|
||||
</qresource>
|
||||
<qresource lang="sk" prefix="/">
|
||||
<qresource prefix="/" lang="sk">
|
||||
<file alias="help">about/help_sk</file>
|
||||
</qresource>
|
||||
<qresource prefix="/help"/>
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ void main(void)
|
||||
vec2 pos = qt_Vertex * 0.5;
|
||||
pos.y *= -1.0;
|
||||
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);
|
||||
qt_TexCoord0 = vec3(qt_MultiTexCoord0, imageSize_num.z + 0.1);
|
||||
|
||||
Binary file not shown.
@@ -30,6 +30,37 @@
|
||||
<translation>File name</translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>HelpDialog</name>
|
||||
<message>
|
||||
@@ -256,6 +287,14 @@
|
||||
<source>FITS/XISF files database</source>
|
||||
<translation>FITS/XISF files database</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>File tree</source>
|
||||
<translation>File tree</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Star finder</source>
|
||||
<translation>Star finder</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MarkedFiles</name>
|
||||
|
||||
Binary file not shown.
@@ -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'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'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'image</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Can't open DB</source>
|
||||
<translation>Ne peut ouvrir la base de donnée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Can'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'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>Ré-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'é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'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'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'é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'étirement automatiquement au chargement</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
Binary file not shown.
@@ -31,6 +31,37 @@
|
||||
<translation>Meno súboru</translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>HelpDialog</name>
|
||||
<message>
|
||||
@@ -269,6 +300,14 @@
|
||||
<source>FITS/XISF files database</source>
|
||||
<translation>Databáza FITS/XISF súborov</translation>
|
||||
</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>
|
||||
<name>MarkedFiles</name>
|
||||
|
||||
Reference in New Issue
Block a user