Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e79133464 | |||
| e08107aa13 | |||
| 6eda2c4e48 | |||
| b16ae3a9ee | |||
| 56bba27ae3 | |||
| 1070dc32c1 | |||
| f61cf12f0a | |||
| 530b0c62c3 | |||
| 7e95440dd6 | |||
| 03492972cb | |||
| 9cca183677 | |||
| afd059b36b | |||
| 1b9f218acb | |||
| 32f91d7b2f | |||
| 69fbad34b6 | |||
| e026042604 | |||
| bb7e5182af | |||
| f0152e2496 | |||
| eccf928032 | |||
| 897306d1c3 |
+17
-3
@@ -61,7 +61,7 @@ This image should be 256 pixel wide. Each row of image will be used as separate
|
|||||||
<li>mid point - defines the value to be stretched to 50% intensity</li>
|
<li>mid point - defines the value to be stretched to 50% intensity</li>
|
||||||
<li>white point - all pixels with higher value (brighter) than this will be clipped white</li>
|
<li>white point - all pixels with higher value (brighter) than this will be clipped white</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Following the slider are 7 buttons for automatic stretching:</p>
|
<p>Following the slider are 8 buttons to control image display:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><i>Linked channels</i> toggle stretching each RGB channel individually.</li>
|
<li><i>Linked channels</i> toggle stretching each RGB channel individually.</li>
|
||||||
<li><i>Auto Stretch</i> automatically apply black and mid points to render the image with optimal brightness.</li>
|
<li><i>Auto Stretch</i> automatically apply black and mid points to render the image with optimal brightness.</li>
|
||||||
@@ -70,6 +70,7 @@ This image should be 256 pixel wide. Each row of image will be used as separate
|
|||||||
<li><i>False colors</i> show black and white in false colour palette.</li>
|
<li><i>False colors</i> show black and white in false colour palette.</li>
|
||||||
<li><i>Debayer CFA</i> Demosaicing black and white image from CFA sensor to color one.</li>
|
<li><i>Debayer CFA</i> Demosaicing black and white image from CFA sensor to color one.</li>
|
||||||
<li><i>Apply Auto stretch on load</i> toggle automatically applying Autostretch for each image when loaded.</li>
|
<li><i>Apply Auto stretch on load</i> toggle automatically applying Autostretch for each image when loaded.</li>
|
||||||
|
<li><i>Draw equatorial grid</i> toggle drawing equatorial coordinate grid and catalogue objects. Needs that file have WCS data.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Marking images</h3>
|
<h3>Marking images</h3>
|
||||||
@@ -134,12 +135,24 @@ solver.
|
|||||||
<p>Then finally there are various action button. Settings button show dialog where you can set path to existing index files or auto download some.
|
<p>Then finally there are various action button. Settings button show dialog where you can set path to existing index files or auto download some.
|
||||||
Extract button will just extract stars from image and it will show their count, HFR and eccentricity. This action doesn't need index files.
|
Extract button will just extract stars from image and it will show their count, HFR and eccentricity. This action doesn't need index files.
|
||||||
Solve button will try to find coordinates of images. Abort button will stop extraction or solving. Update FITS header will update FITS fits keywords
|
Solve button will try to find coordinates of images. Abort button will stop extraction or solving. Update FITS header will update FITS fits keywords
|
||||||
with found solution.
|
with found solution.</p>
|
||||||
|
|
||||||
<p>In settings dialog you can set path to index files which is by default custom internal one. It also try to locate commonly used path from other
|
<p>In settings dialog you can set path to index files which is by default custom internal one. It also try to locate commonly used path from other
|
||||||
programs like KStars for astrometry.net index files.
|
programs like KStars for astrometry.net index files.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3>File Manager</h3>
|
||||||
|
<p>
|
||||||
|
This is simple double panel file manager. It can show columns with selected FITS keywords. Each panel have tabs where it easily switch between
|
||||||
|
multiple directories. You can copy or move files and directories either inside one panel or between two panels by selecting and then dragging.
|
||||||
|
By default files are copies. To move then press Shift key before start dragging. Double click on file will open it in main window if it is image
|
||||||
|
or other file it will open default program that is associated with it this file type. You can also drag file to other programs like from default
|
||||||
|
file explorer programs that are in system or from file explorer to this program.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In menu you can select which FITS keywords will be showed. Temporarilly disable loading FITS header or copy file paths of selected files as text.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3>Batch processing</h3>
|
<h3>Batch processing</h3>
|
||||||
<p>This module allow to write scripts in JavaScript that process image files. Batch Processing window consist from three main parts. On top is list of input files and directories.
|
<p>This module allow to write scripts in JavaScript that process image files. Batch Processing window consist from three main parts. On top is list of input files and directories.
|
||||||
You can add directories or individual files to this list. Directories are scanned recursively to find all files even non image files. This list of files is then passed to script in array named <b>files</b>.
|
You can add directories or individual files to this list. Directories are scanned recursively to find all files even non image files. This list of files is then passed to script in array named <b>files</b>.
|
||||||
@@ -159,7 +172,8 @@ this output directory is ignored.</p>
|
|||||||
<p>Bellow that is list of scripts. These scripts are located in application data directory. Select script which you want to run by clicking on it. Clicking on <i>Open scripts</i> will open directory with these scripts where you create new and edit them.
|
<p>Bellow that is list of scripts. These scripts are located in application data directory. Select script which you want to run by clicking on it. Clicking on <i>Open scripts</i> will open directory with these scripts where you create new and edit them.
|
||||||
Location of this directory is on Windows: "C:/Users/<USER>/AppData/Roaming/nou/Tenmon/scripts" Linux: "~/.local/share/nou/Tenmon/scripts" MacOS: "~/Library/Application Support/nou/Tenmon/scripts"</p>
|
Location of this directory is on Windows: "C:/Users/<USER>/AppData/Roaming/nou/Tenmon/scripts" Linux: "~/.local/share/nou/Tenmon/scripts" MacOS: "~/Library/Application Support/nou/Tenmon/scripts"</p>
|
||||||
|
|
||||||
<p>Next is Log windows that contain any messages that come from scripts. Mainly calls to <code>core.log()</code> At bottom there buttons that can start or stop execution of selected scripts.</p>
|
<p>Next is Log windows that contain any messages that come from scripts. Mainly calls to <code>core.log()</code> At bottom there is console that enable run simple script commands and
|
||||||
|
buttons that can start or stop execution of selected scripts.</p>
|
||||||
|
|
||||||
<h4>core</h4>
|
<h4>core</h4>
|
||||||
<p>There is global object called <b>core</b> that have these methods.</p>
|
<p>There is global object called <b>core</b> that have these methods.</p>
|
||||||
|
|||||||
@@ -51,6 +51,17 @@ na ktorej sa dajú nastaviť tri body.
|
|||||||
<li>stredný bod - pixeli s touto hodnotou budú zobrazené ako 50% šedá</li>
|
<li>stredný bod - pixeli s touto hodnotou budú zobrazené ako 50% šedá</li>
|
||||||
<li>biely bod - pixeli nad touto hodnotou budú zobrazené ako biele</li>
|
<li>biely bod - pixeli nad touto hodnotou budú zobrazené ako biele</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<p>Nasleduje 8 tlačidiel pre nastavenie zobrazenie obrázka:</p>
|
||||||
|
<ul>
|
||||||
|
<li><i>Prepojené kanály</i> prepína medzi nataihnutím jasových urovní pre každý RGB kanál zvlášť alebo jednotné pre všetky kanály.</li>
|
||||||
|
<li><i>Automatické natiahnutie</i> automaticky nastavý čierny, šedý a biely bod pre optimálne zobrazenie..</li>
|
||||||
|
<li><i>Resetuj funkciu prevodu na obrazovku</i> nastavý hodnoty čierneho, šedého a bieleho bodu na východzie hodnoty.</li>
|
||||||
|
<li><i>Invertuj farby</i> invertuje zobrazené farby a zobrazý obrázok ako negatív.</li>
|
||||||
|
<li><i>Falošné farby</i> pre zobrazenie čiernobielych obrázkov sa použije farebná paleta.</li>
|
||||||
|
<li><i>Preved CFA na farbu</i> Demosaicing black and white image from CFA sensor to color one.</li>
|
||||||
|
<li><i>Aplikuj automatické natiahnutie pri načítaní</i> pri zapnutí </li>
|
||||||
|
<li><i>Vykresli equatoriálnu mriežku</i> zapína zobrazenie equatoriálnej mriežky. Je poitrebné aby súbor obsahoval WCS dáta.</li>
|
||||||
|
</ul>
|
||||||
<p>Prvé tlačidlo prepína prepojenie nastavenia čierneho, stretdného a bieleho bodu. Po prepnutí sa dá každý farebný kanál nastaviť
|
<p>Prvé tlačidlo prepína prepojenie nastavenia čierneho, stretdného a bieleho bodu. Po prepnutí sa dá každý farebný kanál nastaviť
|
||||||
samostatne.
|
samostatne.
|
||||||
Nasleduje tlačidlo ktoré nastaví hodnoty čierneho a stredného bodu tak aby bol obrázok zobrazený optimálnym jasom.
|
Nasleduje tlačidlo ktoré nastaví hodnoty čierneho a stredného bodu tak aby bol obrázok zobrazený optimálnym jasom.
|
||||||
@@ -94,6 +105,34 @@ V nasledovnom príklade sa vyhľadajú súbory ktoré majú v mene súboru "Bias
|
|||||||
zástupný znak za hocijaký reťazec znakov aj žiadny. Znak _ je tiež zástupný znak zastupujúci práve jeden znak.
|
zástupný znak za hocijaký reťazec znakov aj žiadny. Znak _ je tiež zástupný znak zastupujúci práve jeden znak.
|
||||||
Bez použitia zástupných znakov sa vyhľadá iba presný výskyt.</p>
|
Bez použitia zástupných znakov sa vyhľadá iba presný výskyt.</p>
|
||||||
|
|
||||||
|
<h3>Plate Solving</h3>
|
||||||
|
<p>Tento modul umožnuje vyriešiť obrázok a určiť RA, DEC koordináty a aktualizovať FITS a XISF súbory s WCS dátami.
|
||||||
|
<b>Profil</b> toto nastavuje rôzne parametre ovplivňujúce extrahovanie hviezd a hľadanie koordinátov.
|
||||||
|
<b>Štartovný bod</b> program sa pokúsi automaticky určiť bod začiatku hľadania koordinátov pre zrýchlenie hľadania.
|
||||||
|
Možete nechať jednu alebo obydve voľbi nezaškrtnuté kedy sa bude hľadať riešenie naslepo. Ak je pozícia alebo škála nesprávna hľadanie môže zlyhať.
|
||||||
|
<b>Riešenie</b> táto časť obsahuje výsledné riešenie hľadania ako sú RA,DEC koordináty stredu obrázku, veľkosť zorného poľa, uhol natočenia v stupňoch,
|
||||||
|
škála obrázku v arcsekundách na pixel, počet nájdených hviezd a veľkosť hviezd HFR a excentricita. Potom je tu ešte okno so záznamom z riešenia.
|
||||||
|
</p>
|
||||||
|
<p>Pod tým je tlačidlo pre nastavenie cesty k indexovým súborom a ich stiahnutie. Je možné buď stiahnuť indexové súbory alebo použiť už existujúce súbory.
|
||||||
|
Tlačidlo Extrahovať nájde hviezdy a zobrazý ich počet veľkosť HFR a excentricitu. Na toto nie sú potrebné indexové súbory.
|
||||||
|
Tlačidlo Vyriešiť sa pokúsi nájsť koordináty obrázka. Zrušiť preruší hľadanie riešenia. Aktualizovať FITS hlavičku zapíše najdené riešenie do súboru.</p>
|
||||||
|
|
||||||
|
<p>In settings dialog you can set path to index files which is by default custom internal one. It also try to locate commonly used path from other
|
||||||
|
programs like KStars for astrometry.net index files.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>File Manager</h3>
|
||||||
|
<p>
|
||||||
|
This is simple double panel file manager. It can show columns with selected FITS keywords. Each panel have tabs where it easily switch between
|
||||||
|
multiple directories. You can copy or move files and directories either inside one panel or between two panels by selecting and then dragging.
|
||||||
|
By default files are copies. To move then press Shift key before start dragging. Double click on file will open it in main window if it is image
|
||||||
|
or other file it will open default program that is associated with it this file type. You can also drag file to other programs like from default
|
||||||
|
file explorer programs that are in system or from file explorer to this program.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In menu you can select which FITS keywords will be showed. Temporarilly disable loading FITS header or copy file paths of selected files as text.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3>Hromadné spracovanie</h3>
|
<h3>Hromadné spracovanie</h3>
|
||||||
|
|
||||||
Tento modul umožnuje písanie skriptov v JavaScripte ktoré spracujú súbory obrázkov. Okno Hromadného spracovanie pozostáva z troch častí. Navrchu je zoznam vstupných súborov a adresárov.
|
Tento modul umožnuje písanie skriptov v JavaScripte ktoré spracujú súbory obrázkov. Okno Hromadného spracovanie pozostáva z troch častí. Navrchu je zoznam vstupných súborov a adresárov.
|
||||||
@@ -109,6 +148,12 @@ V skripte potom cez toto pole iteruje nasledovne.
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<p>Pod týmto zoznamom je výstupný adresár. Všetky relatívne cesty predané do metod ako sú copy(), move() alebo convert() budú relatívne voči tomuto adresáru.
|
||||||
|
Ak je ako argument použitá absolútna cesta tak je tento vystupný adresár ignorovaný.</p>
|
||||||
|
|
||||||
|
<p>Nasleduje logovacie okno kde sú zapisováné všetký výpisy z behu scriptu. Hlavne volania z <code>core.log()</code> Na spodu je konzola kde je možné vkladať jednoduché príkazy a nakoniec ešte tlačítka
|
||||||
|
ktoré spúštať alebo zastavovať vybraný skript.</p>
|
||||||
|
|
||||||
<h4>core</h4>
|
<h4>core</h4>
|
||||||
V skripte je dostupný globálny objekt nazvaný <b>core</b> ktorý má nasledovné metódy.
|
V skripte je dostupný globálny objekt nazvaný <b>core</b> ktorý má nasledovné metódy.
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
+1
-1
Submodule libXISF updated: fa39440b9e...2e74d94641
@@ -33,6 +33,7 @@
|
|||||||
<li>Color space aware</li>
|
<li>Color space aware</li>
|
||||||
<li>Histogram</li>
|
<li>Histogram</li>
|
||||||
<li>Scripting</li>
|
<li>Scripting</li>
|
||||||
|
<li>Plate solving</li>
|
||||||
</ul>
|
</ul>
|
||||||
</description>
|
</description>
|
||||||
<categories>
|
<categories>
|
||||||
@@ -58,6 +59,25 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
<content_rating type="oars-1.1"/>
|
<content_rating type="oars-1.1"/>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="20251101" date="2025-11-01">
|
||||||
|
<description>
|
||||||
|
<ul>
|
||||||
|
<li>Better image Save as</li>
|
||||||
|
<li>Fix xisf file corruption when platesolving</li>
|
||||||
|
<li>Add selecting language</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="20250915" date="2025-09-15">
|
||||||
|
<description>
|
||||||
|
<ul>
|
||||||
|
<li>Draw equatorial grid and objects overlay</li>
|
||||||
|
<li>File Manager</li>
|
||||||
|
<li>Support for PCL:AstrometricSolution</li>
|
||||||
|
<li>Script console</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="20250429" date="2025-04-29">
|
<release version="20250429" date="2025-04-29">
|
||||||
<description>
|
<description>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -118,7 +138,7 @@
|
|||||||
</release>
|
</release>
|
||||||
<release version="20240816" date="2024-08-16">
|
<release version="20240816" date="2024-08-16">
|
||||||
<description>
|
<description>
|
||||||
Fix saving image
|
<p>Fix saving image</p>
|
||||||
</description>
|
</description>
|
||||||
</release>
|
</release>
|
||||||
<release version="20240616" date="2024-06-16">
|
<release version="20240616" date="2024-06-16">
|
||||||
|
|||||||
+83
-4
@@ -13,6 +13,7 @@
|
|||||||
#include <QChart>
|
#include <QChart>
|
||||||
#include <QChartView>
|
#include <QChartView>
|
||||||
#include <QLineSeries>
|
#include <QLineSeries>
|
||||||
|
#include <QCompleter>
|
||||||
#include "scriptengine.h"
|
#include "scriptengine.h"
|
||||||
#include "chartgraph.h"
|
#include "chartgraph.h"
|
||||||
|
|
||||||
@@ -110,6 +111,31 @@ BatchProcessing::BatchProcessing(Database *database, QWidget *parent) : QDialog(
|
|||||||
|
|
||||||
_textColor = _ui->log->palette().text().color();
|
_textColor = _ui->log->palette().text().color();
|
||||||
|
|
||||||
|
_engine = new Script::ScriptEngine(_database, this);
|
||||||
|
connect(_engine, &Script::ScriptEngine::newMessage, this, &BatchProcessing::newMessage);
|
||||||
|
|
||||||
|
_completerModel = new QStringListModel(this);
|
||||||
|
_completer = new QCompleter(_completerModel, this);
|
||||||
|
_ui->consoleLineEdit->setCompleter(_completer);
|
||||||
|
connect(_ui->executeButton, &QPushButton::clicked, _ui->consoleLineEdit, &QLineEdit::returnPressed);
|
||||||
|
connect(_ui->consoleLineEdit, &QLineEdit::returnPressed, [this](){
|
||||||
|
if(!_completer->popup()->isVisible())
|
||||||
|
{
|
||||||
|
QString program = _ui->consoleLineEdit->text();
|
||||||
|
QJSValue val = _engine->eval(program);
|
||||||
|
_ui->consoleLineEdit->addLine();
|
||||||
|
//qDebug() << val.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(_ui->consoleLineEdit, &QLineEdit::textEdited, [this](const QString &text){
|
||||||
|
QStringList comp = _engine->complete(text);
|
||||||
|
//qDebug() << comp;
|
||||||
|
_completerModel->setStringList(comp);
|
||||||
|
});
|
||||||
|
|
||||||
|
_ui->addFilesButton->setAutoDefault(false);
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
_ui->outputPath->setText(settings.value("batchprocessing/outputpath", QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first()).toString());
|
_ui->outputPath->setText(settings.value("batchprocessing/outputpath", QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first()).toString());
|
||||||
}
|
}
|
||||||
@@ -143,6 +169,15 @@ void BatchProcessing::closeEvent(QCloseEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::refreshPaths()
|
||||||
|
{
|
||||||
|
QStringList paths;
|
||||||
|
for(int i=0; i<_ui->pathsList->count(); i++)
|
||||||
|
paths.append(_ui->pathsList->item(i)->text());
|
||||||
|
_paths = scanDirectories(paths);
|
||||||
|
_engine->setParams("", _paths, _ui->outputPath->text());
|
||||||
|
}
|
||||||
|
|
||||||
void BatchProcessing::addFiles()
|
void BatchProcessing::addFiles()
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
@@ -152,6 +187,7 @@ void BatchProcessing::addFiles()
|
|||||||
_ui->pathsList->addItems(files);
|
_ui->pathsList->addItems(files);
|
||||||
settings.setValue("batchprocessing/inputpath", QFileInfo(files.first()).absolutePath());
|
settings.setValue("batchprocessing/inputpath", QFileInfo(files.first()).absolutePath());
|
||||||
}
|
}
|
||||||
|
refreshPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatchProcessing::addDir()
|
void BatchProcessing::addDir()
|
||||||
@@ -163,6 +199,7 @@ void BatchProcessing::addDir()
|
|||||||
_ui->pathsList->addItem(dir);
|
_ui->pathsList->addItem(dir);
|
||||||
settings.setValue("batchprocessing/inputpath", dir);
|
settings.setValue("batchprocessing/inputpath", dir);
|
||||||
}
|
}
|
||||||
|
refreshPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatchProcessing::addMarked()
|
void BatchProcessing::addMarked()
|
||||||
@@ -174,17 +211,20 @@ void BatchProcessing::addMarked()
|
|||||||
if(info.exists() && info.isReadable())
|
if(info.exists() && info.isReadable())
|
||||||
_ui->pathsList->addItem(file);
|
_ui->pathsList->addItem(file);
|
||||||
};
|
};
|
||||||
|
refreshPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatchProcessing::removePath()
|
void BatchProcessing::removePath()
|
||||||
{
|
{
|
||||||
for(auto &item : _ui->pathsList->selectedItems())
|
for(auto &item : _ui->pathsList->selectedItems())
|
||||||
delete item;
|
delete item;
|
||||||
|
refreshPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatchProcessing::removeAllPaths()
|
void BatchProcessing::removeAllPaths()
|
||||||
{
|
{
|
||||||
_ui->pathsList->clear();
|
_ui->pathsList->clear();
|
||||||
|
refreshPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatchProcessing::browse()
|
void BatchProcessing::browse()
|
||||||
@@ -208,9 +248,6 @@ void BatchProcessing::runScript()
|
|||||||
_engineThread = new Script::ScriptEngineThread(_database, this);
|
_engineThread = new Script::ScriptEngineThread(_database, this);
|
||||||
connect(_engineThread, &Script::ScriptEngineThread::newMessage, this, &BatchProcessing::newMessage);
|
connect(_engineThread, &Script::ScriptEngineThread::newMessage, this, &BatchProcessing::newMessage);
|
||||||
connect(_engineThread, &Script::ScriptEngineThread::finished, this, &BatchProcessing::scriptFinished);
|
connect(_engineThread, &Script::ScriptEngineThread::finished, this, &BatchProcessing::scriptFinished);
|
||||||
QStringList paths;
|
|
||||||
for(int i=0; i<_ui->pathsList->count(); i++)
|
|
||||||
paths.append(_ui->pathsList->item(i)->text());
|
|
||||||
|
|
||||||
QFileInfo outDir(_ui->outputPath->text());
|
QFileInfo outDir(_ui->outputPath->text());
|
||||||
if(outDir.exists() && outDir.isWritable())
|
if(outDir.exists() && outDir.isWritable())
|
||||||
@@ -221,7 +258,7 @@ void BatchProcessing::runScript()
|
|||||||
else
|
else
|
||||||
script = ":/scripts/" + script;
|
script = ":/scripts/" + script;
|
||||||
|
|
||||||
_engineThread->setParams(script, scanDirectories(paths), _ui->outputPath->text());
|
_engineThread->setParams(script, _paths, _ui->outputPath->text());
|
||||||
_engineThread->start();
|
_engineThread->start();
|
||||||
_ui->startButton->setEnabled(false);
|
_ui->startButton->setEnabled(false);
|
||||||
_ui->stopButton->setEnabled(true);
|
_ui->stopButton->setEnabled(true);
|
||||||
@@ -329,6 +366,48 @@ void BatchProcessing::plot(const QVariant &graph)
|
|||||||
chart->plot(graph);
|
chart->plot(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConsoleLine::ConsoleLine(QWidget *parent) : QLineEdit(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleLine::addLine()
|
||||||
|
{
|
||||||
|
QString line = text();
|
||||||
|
clear();
|
||||||
|
if(_history.size() && _history.last() == line)return;
|
||||||
|
|
||||||
|
_history.append(line);
|
||||||
|
if(_history.size() > 100)_history.removeFirst();
|
||||||
|
_currentLine = _history.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleLine::keyReleaseEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if(event->key() == Qt::Key_Up)
|
||||||
|
{
|
||||||
|
_currentLine--;
|
||||||
|
if(_currentLine < 0)
|
||||||
|
{
|
||||||
|
_currentLine = -1;
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setText(_history.at(_currentLine));
|
||||||
|
}
|
||||||
|
else if(event->key() == Qt::Key_Down)
|
||||||
|
{
|
||||||
|
_currentLine++;
|
||||||
|
if(_currentLine >= _history.size())
|
||||||
|
{
|
||||||
|
_currentLine = _history.size();
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setText(_history.at(_currentLine));
|
||||||
|
}
|
||||||
|
else QLineEdit::keyReleaseEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
void openDir(const QString &path)
|
void openDir(const QString &path)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
|
#include <QStringListModel>
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QLineEdit>
|
||||||
#include "scriptengine.h"
|
#include "scriptengine.h"
|
||||||
|
|
||||||
namespace Ui { class BatchProcessing; }
|
namespace Ui { class BatchProcessing; }
|
||||||
@@ -16,8 +19,12 @@ class BatchProcessing : public QDialog
|
|||||||
QString _scriptBasePath;
|
QString _scriptBasePath;
|
||||||
QFileSystemWatcher _fileWatcher;
|
QFileSystemWatcher _fileWatcher;
|
||||||
Script::ScriptEngineThread *_engineThread = nullptr;
|
Script::ScriptEngineThread *_engineThread = nullptr;
|
||||||
|
Script::ScriptEngine *_engine = nullptr;
|
||||||
QColor _textColor;
|
QColor _textColor;
|
||||||
Database *_database;
|
Database *_database;
|
||||||
|
QStringListModel *_completerModel = nullptr;
|
||||||
|
QCompleter *_completer = nullptr;
|
||||||
|
QList<QPair<QString, QString>> _paths;
|
||||||
private slots:
|
private slots:
|
||||||
void scanScriptDir();
|
void scanScriptDir();
|
||||||
public:
|
public:
|
||||||
@@ -25,6 +32,7 @@ public:
|
|||||||
~BatchProcessing();
|
~BatchProcessing();
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent *event);
|
void closeEvent(QCloseEvent *event);
|
||||||
|
void refreshPaths();
|
||||||
public slots:
|
public slots:
|
||||||
void addFiles();
|
void addFiles();
|
||||||
void addDir();
|
void addDir();
|
||||||
@@ -47,6 +55,18 @@ public slots:
|
|||||||
void plot(const QVariant &graph);
|
void plot(const QVariant &graph);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ConsoleLine : public QLineEdit
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ConsoleLine(QWidget *parent = nullptr);
|
||||||
|
void addLine();
|
||||||
|
void keyReleaseEvent(QKeyEvent *event) override;
|
||||||
|
private:
|
||||||
|
int _currentLine = 0;
|
||||||
|
QStringList _history;
|
||||||
|
};
|
||||||
|
|
||||||
void openDir(const QString &path);
|
void openDir(const QString &path);
|
||||||
|
|
||||||
#endif // BATCHPROCESSING_H
|
#endif // BATCHPROCESSING_H
|
||||||
|
|||||||
+63
-33
@@ -43,6 +43,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add files</string>
|
<string>Add files</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -50,6 +53,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add directories</string>
|
<string>Add directories</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -57,6 +63,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add marked</string>
|
<string>Add marked</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -64,6 +73,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Remove</string>
|
<string>Remove</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -71,6 +83,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Remove all</string>
|
<string>Remove all</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@@ -98,6 +113,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Browse</string>
|
<string>Browse</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@@ -129,6 +147,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open scripts</string>
|
<string>Open scripts</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@@ -171,23 +192,30 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_2">
|
<widget class="ConsoleLine" name="consoleLineEdit">
|
||||||
<property name="orientation">
|
<property name="placeholderText">
|
||||||
<enum>Qt::Horizontal</enum>
|
<string>Console</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
</widget>
|
||||||
<size>
|
</item>
|
||||||
<width>40</width>
|
<item>
|
||||||
<height>20</height>
|
<widget class="QPushButton" name="executeButton">
|
||||||
</size>
|
<property name="text">
|
||||||
|
<string>Execute</string>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="startButton">
|
<widget class="QPushButton" name="startButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Start script</string>
|
<string>Start script</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -198,12 +226,8 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stop script</string>
|
<string>Stop script</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="autoDefault">
|
||||||
</item>
|
<bool>false</bool>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="closeButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Close</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -211,23 +235,29 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>ConsoleLine</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>batchprocessing.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>pathsList</tabstop>
|
||||||
|
<tabstop>addFilesButton</tabstop>
|
||||||
|
<tabstop>addDirButton</tabstop>
|
||||||
|
<tabstop>addMarkedButton</tabstop>
|
||||||
|
<tabstop>removeButton</tabstop>
|
||||||
|
<tabstop>removeAllButton</tabstop>
|
||||||
|
<tabstop>browseButton</tabstop>
|
||||||
|
<tabstop>openScriptsButton</tabstop>
|
||||||
|
<tabstop>scriptsList</tabstop>
|
||||||
|
<tabstop>consoleLineEdit</tabstop>
|
||||||
|
<tabstop>startButton</tabstop>
|
||||||
|
<tabstop>stopButton</tabstop>
|
||||||
|
<tabstop>outputPath</tabstop>
|
||||||
|
<tabstop>log</tabstop>
|
||||||
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections/>
|
||||||
<connection>
|
|
||||||
<sender>closeButton</sender>
|
|
||||||
<signal>released()</signal>
|
|
||||||
<receiver>BatchProcessing</receiver>
|
|
||||||
<slot>close()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>973</x>
|
|
||||||
<y>745</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>511</x>
|
|
||||||
<y>383</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
+371
-16
@@ -5,18 +5,224 @@
|
|||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QDirIterator>
|
||||||
#include "loadimage.h"
|
#include "loadimage.h"
|
||||||
|
|
||||||
|
class FileTimes
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit FileTimes(const QString &path)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
|
birthTime = file.fileTime(QFileDevice::FileBirthTime);
|
||||||
|
#endif
|
||||||
|
modificationTime = file.fileTime(QFileDevice::FileModificationTime);
|
||||||
|
accessTime = file.fileTime(QFileDevice::FileAccessTime);
|
||||||
|
}
|
||||||
|
void apply(const QString &path)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
if(file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::ExistingOnly))
|
||||||
|
{
|
||||||
|
#ifndef Q_OS_WIN // Only windows allow changing birth time
|
||||||
|
file.setFileTime(birthTime, QFileDevice::FileBirthTime);
|
||||||
|
#endif
|
||||||
|
file.setFileTime(accessTime, QFileDevice::FileAccessTime);
|
||||||
|
file.setFileTime(modificationTime, QFileDevice::FileModificationTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
QDateTime birthTime;
|
||||||
|
QDateTime modificationTime;
|
||||||
|
QDateTime accessTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
FileTransfer::FileTransfer(FileManager *fm) :
|
||||||
|
_fm(fm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileTransfer::~FileTransfer()
|
||||||
|
{
|
||||||
|
_run = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTransfer::copy(const QStringList &src, const QString &dst)
|
||||||
|
{
|
||||||
|
_run = true;
|
||||||
|
perform(src, dst, true);
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTransfer::move(const QStringList &src, const QString &dst)
|
||||||
|
{
|
||||||
|
_run = true;
|
||||||
|
perform(src, dst, false);
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTransfer::cancel()
|
||||||
|
{
|
||||||
|
_run = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTransfer::perform(const QStringList &src, const QString &dst, bool copy)
|
||||||
|
{
|
||||||
|
QDir dstDir(dst);
|
||||||
|
if(!dstDir.exists())
|
||||||
|
{
|
||||||
|
emit error(tr("Error"), tr("Destination directory %1 doesn't exists").arg(dstDir.absolutePath()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Action> actions;
|
||||||
|
QStringList dirs;
|
||||||
|
|
||||||
|
emit progress(0);
|
||||||
|
|
||||||
|
for(const QString &i : src)
|
||||||
|
{
|
||||||
|
QFileInfo srcInfo(i);
|
||||||
|
if(srcInfo.absolutePath() == dst || dst.startsWith(srcInfo.absoluteFilePath()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(srcInfo.isDir())
|
||||||
|
{
|
||||||
|
QDir srcDir(i);
|
||||||
|
//qDebug() << "dir" << srcInfo.absoluteFilePath() << srcInfo.fileName();
|
||||||
|
if(!copy && !dstDir.exists(srcInfo.fileName()))
|
||||||
|
{
|
||||||
|
if(QFile::rename(srcInfo.absoluteFilePath(), dstDir.absoluteFilePath(srcInfo.fileName())))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
actions.append({srcInfo.absoluteFilePath(), srcInfo.fileName(), true});
|
||||||
|
if(!copy)dirs.prepend(srcInfo.absoluteFilePath());
|
||||||
|
QDirIterator it(i, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
QFileInfo info = it.nextFileInfo();
|
||||||
|
if(info.fileName() == "." || info.fileName() == "..")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QString relativePath = srcDir.dirName() + "/" + srcDir.relativeFilePath(info.absoluteFilePath());
|
||||||
|
if(info.isDir())
|
||||||
|
{
|
||||||
|
actions.append({"", relativePath, true});
|
||||||
|
if(!copy)dirs.prepend(info.absoluteFilePath());
|
||||||
|
//qDebug() << "dir" << info.absoluteFilePath() << relativePath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actions.append({info.absoluteFilePath(), dstDir.absoluteFilePath(relativePath), false});
|
||||||
|
//qDebug() << "file" << info.absoluteFilePath() << dstDir.absoluteFilePath(relativePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actions.append({srcInfo.absoluteFilePath(), dstDir.absoluteFilePath(srcInfo.fileName())});
|
||||||
|
//qDebug() << "file" << srcInfo.absoluteFilePath() << dstDir.absoluteFilePath(srcInfo.fileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overwriteAll = false;
|
||||||
|
bool skipAll = false;
|
||||||
|
int total = actions.size();
|
||||||
|
int i = 0;
|
||||||
|
for(auto &a : actions)
|
||||||
|
{
|
||||||
|
if(!_run)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(a.dir)
|
||||||
|
{
|
||||||
|
dstDir.mkpath(a.dst);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QFileInfo dstInfo(a.dst);
|
||||||
|
if(dstInfo.exists())
|
||||||
|
{
|
||||||
|
if(overwriteAll)
|
||||||
|
{
|
||||||
|
QFile::remove(dstInfo.absoluteFilePath());
|
||||||
|
}
|
||||||
|
else if(skipAll)
|
||||||
|
{
|
||||||
|
emit progress(i++ * 100 / total);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::StandardButton ret;
|
||||||
|
QMetaObject::invokeMethod(_fm, "overwrite", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QMessageBox::StandardButton, ret), Q_ARG(QString, dstInfo.fileName()));
|
||||||
|
switch(ret)
|
||||||
|
{
|
||||||
|
case QMessageBox::YesToAll:
|
||||||
|
overwriteAll = true;//break; is intentionally missing
|
||||||
|
case QMessageBox::Yes:
|
||||||
|
QFile::remove(dstInfo.absoluteFilePath());
|
||||||
|
break;
|
||||||
|
case QMessageBox::NoToAll:
|
||||||
|
skipAll = true;//break; is intentionally missing
|
||||||
|
case QMessageBox::No:
|
||||||
|
emit progress(i++ * 100 / total);
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case QMessageBox::Cancel:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FileTimes t(a.src);
|
||||||
|
if(copy)
|
||||||
|
{
|
||||||
|
if(!QFile::copy(a.src, a.dst))
|
||||||
|
{
|
||||||
|
emit error(tr("Copy failed"), tr("Failed to copy file %1 to %2").arg(a.src).arg(a.dst));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!QFile::rename(a.src, a.dst))
|
||||||
|
{
|
||||||
|
emit error(tr("Move failed"), tr("Failed to move file %1 to %2").arg(a.src).arg(a.dst));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.apply(a.dst);
|
||||||
|
}
|
||||||
|
emit progress(i++ * 100 / total);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!copy)
|
||||||
|
{
|
||||||
|
for(const QString &d : dirs)
|
||||||
|
{
|
||||||
|
QDir dir(d);
|
||||||
|
if(dir.isEmpty())
|
||||||
|
dir.removeRecursively();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PathTabBar::PathTabBar(const QStringList &tabs) :
|
PathTabBar::PathTabBar(const QStringList &tabs) :
|
||||||
_tabs(tabs)
|
_tabs(tabs)
|
||||||
{
|
{
|
||||||
setTabsClosable(true);
|
setTabsClosable(true);
|
||||||
setExpanding(false);
|
setExpanding(false);
|
||||||
|
|
||||||
for(auto &t : tabs)
|
for(auto &t : _tabs)
|
||||||
{
|
{
|
||||||
QDir dir(t);
|
QDir dir(t);
|
||||||
int i = addTab(dir.dirName());
|
int i = addTab(tabName(t));
|
||||||
setTabToolTip(i, t);
|
setTabToolTip(i, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,9 +251,8 @@ QHBoxLayout *PathTabBar::createLayout()
|
|||||||
QPushButton *addButton = new QPushButton("+");
|
QPushButton *addButton = new QPushButton("+");
|
||||||
connect(addButton, &QPushButton::clicked, [this](){
|
connect(addButton, &QPushButton::clicked, [this](){
|
||||||
QString path = _tabs[currentIndex()];
|
QString path = _tabs[currentIndex()];
|
||||||
QDir dir(path);
|
|
||||||
_tabs.append(path);
|
_tabs.append(path);
|
||||||
int i = addTab(dir.dirName());
|
int i = addTab(tabName(path));
|
||||||
setTabToolTip(i, path);
|
setTabToolTip(i, path);
|
||||||
});
|
});
|
||||||
hlayout->addWidget(addButton);
|
hlayout->addWidget(addButton);
|
||||||
@@ -69,11 +274,20 @@ void PathTabBar::pathChanged(const QString &path)
|
|||||||
{
|
{
|
||||||
QDir dir(path);
|
QDir dir(path);
|
||||||
int index = currentIndex();
|
int index = currentIndex();
|
||||||
setTabText(index, dir.dirName());
|
setTabText(index, tabName(path));
|
||||||
setTabToolTip(index, path);
|
setTabToolTip(index, path);
|
||||||
_tabs[index] = path;
|
_tabs[index] = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString PathTabBar::tabName(const QString &path)
|
||||||
|
{
|
||||||
|
QDir dir(path);
|
||||||
|
if(dir.dirName().isEmpty())
|
||||||
|
return path;
|
||||||
|
else
|
||||||
|
return dir.dirName();
|
||||||
|
}
|
||||||
|
|
||||||
FITSSelection::FITSSelection(const QStringList &keywords, QWidget *parent) : QDialog(parent)
|
FITSSelection::FITSSelection(const QStringList &keywords, QWidget *parent) : QDialog(parent)
|
||||||
,ui(new Ui::FITSKeyword)
|
,ui(new Ui::FITSKeyword)
|
||||||
{
|
{
|
||||||
@@ -139,6 +353,8 @@ FileManager::FileManager(const QSet<QString> &openFilter, QWidget *parent) : QMa
|
|||||||
connect(ui->rightTab, &DirView::dirChanged, _rightTabBar, &PathTabBar::pathChanged);
|
connect(ui->rightTab, &DirView::dirChanged, _rightTabBar, &PathTabBar::pathChanged);
|
||||||
connect(ui->leftTab, &DirView::openFile, this, &FileManager::openFile);
|
connect(ui->leftTab, &DirView::openFile, this, &FileManager::openFile);
|
||||||
connect(ui->rightTab, &DirView::openFile, this, &FileManager::openFile);
|
connect(ui->rightTab, &DirView::openFile, this, &FileManager::openFile);
|
||||||
|
connect(ui->leftTab, &DirView::filesAction, this, &FileManager::copyMoveFiles, Qt::QueuedConnection);
|
||||||
|
connect(ui->rightTab, &DirView::filesAction, this, &FileManager::copyMoveFiles, Qt::QueuedConnection);
|
||||||
connect(ui->actionLoad_FITS_keywordsLeft, &QAction::toggled, ui->leftTab, &DirView::loadFitsKeywords);
|
connect(ui->actionLoad_FITS_keywordsLeft, &QAction::toggled, ui->leftTab, &DirView::loadFitsKeywords);
|
||||||
connect(ui->actionLoad_FITS_keywordsRight, &QAction::toggled, ui->rightTab, &DirView::loadFitsKeywords);
|
connect(ui->actionLoad_FITS_keywordsRight, &QAction::toggled, ui->rightTab, &DirView::loadFitsKeywords);
|
||||||
|
|
||||||
@@ -157,6 +373,10 @@ FileManager::FileManager(const QSet<QString> &openFilter, QWidget *parent) : QMa
|
|||||||
|
|
||||||
connect(ui->actionSelect_columnsLeft, &QAction::triggered, this, &FileManager::selectFITSKeywords);
|
connect(ui->actionSelect_columnsLeft, &QAction::triggered, this, &FileManager::selectFITSKeywords);
|
||||||
connect(ui->actionSelect_columnsRight, &QAction::triggered, this, &FileManager::selectFITSKeywords);
|
connect(ui->actionSelect_columnsRight, &QAction::triggered, this, &FileManager::selectFITSKeywords);
|
||||||
|
connect(ui->actionCopySelectedFilesPathsLeft, &QAction::triggered, this, &FileManager::copySelectedFilesPaths);
|
||||||
|
connect(ui->actionCopySelectedFilesPathsRight, &QAction::triggered, this, &FileManager::copySelectedFilesPaths);
|
||||||
|
connect(ui->leftPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited);
|
||||||
|
connect(ui->rightPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited);
|
||||||
|
|
||||||
QFileInfoList drives = QDir::drives();
|
QFileInfoList drives = QDir::drives();
|
||||||
for(auto &drive : drives)
|
for(auto &drive : drives)
|
||||||
@@ -165,6 +385,25 @@ FileManager::FileManager(const QSet<QString> &openFilter, QWidget *parent) : QMa
|
|||||||
ui->menuLeft_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->leftTab->setDir(path); });
|
ui->menuLeft_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->leftTab->setDir(path); });
|
||||||
ui->menuRight_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->rightTab->setDir(path); });
|
ui->menuRight_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->rightTab->setDir(path); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui->progressBar->hide();
|
||||||
|
ui->cancelButton->hide();
|
||||||
|
|
||||||
|
_thread = new QThread(this);
|
||||||
|
_thread->start();
|
||||||
|
_fileTransfer = new FileTransfer(this);
|
||||||
|
_fileTransfer->moveToThread(_thread);
|
||||||
|
connect(_fileTransfer, &FileTransfer::progress, ui->progressBar, &QProgressBar::setValue);
|
||||||
|
connect(_fileTransfer, &FileTransfer::error, this, &FileManager::errorMessage);
|
||||||
|
connect(_fileTransfer, &FileTransfer::finished, [this](){
|
||||||
|
ui->leftTab->setDragEnabled(true);
|
||||||
|
ui->rightTab->setDragEnabled(true);
|
||||||
|
ui->progressBar->hide();
|
||||||
|
ui->cancelButton->hide();
|
||||||
|
});
|
||||||
|
connect(this, &FileManager::copy, _fileTransfer, &FileTransfer::copy);
|
||||||
|
connect(this, &FileManager::move, _fileTransfer, &FileTransfer::move);
|
||||||
|
connect(ui->cancelButton, &QPushButton::clicked, [this](){ _fileTransfer->cancel(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
FileManager::~FileManager()
|
FileManager::~FileManager()
|
||||||
@@ -180,6 +419,12 @@ FileManager::~FileManager()
|
|||||||
settings.setValue("filemanager/rightLoadFitsKeywords", ui->actionLoad_FITS_keywordsRight->isChecked());
|
settings.setValue("filemanager/rightLoadFitsKeywords", ui->actionLoad_FITS_keywordsRight->isChecked());
|
||||||
settings.setValue("filemanager/geometry", saveGeometry());
|
settings.setValue("filemanager/geometry", saveGeometry());
|
||||||
delete ui;
|
delete ui;
|
||||||
|
|
||||||
|
_fileTransfer->cancel();
|
||||||
|
_thread->quit();
|
||||||
|
_thread->wait();
|
||||||
|
|
||||||
|
delete _fileTransfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileManager::selectFITSKeywords()
|
void FileManager::selectFITSKeywords()
|
||||||
@@ -203,9 +448,62 @@ void FileManager::selectFITSKeywords()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileManager::addTab()
|
void FileManager::copySelectedFilesPaths()
|
||||||
{
|
{
|
||||||
|
if(sender() == ui->actionCopySelectedFilesPathsLeft)
|
||||||
|
ui->leftTab->copySelectedFilesPathsToClipboard();
|
||||||
|
if(sender() == ui->actionCopySelectedFilesPathsRight)
|
||||||
|
ui->rightTab->copySelectedFilesPathsToClipboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::pathEdited()
|
||||||
|
{
|
||||||
|
if(sender() == ui->leftPath)
|
||||||
|
{
|
||||||
|
QDir dir(ui->leftPath->text());
|
||||||
|
if(dir.exists())
|
||||||
|
ui->leftTab->setDir(dir.absolutePath());
|
||||||
|
}
|
||||||
|
if(sender() == ui->rightPath)
|
||||||
|
{
|
||||||
|
QDir dir(ui->rightPath->text());
|
||||||
|
if(dir.exists())
|
||||||
|
ui->rightTab->setDir(dir.absolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::copyMoveFiles(Qt::DropAction action, const QStringList &src, const QString &dst)
|
||||||
|
{
|
||||||
|
ui->leftTab->setDragEnabled(false);
|
||||||
|
ui->rightTab->setDragEnabled(false);
|
||||||
|
ui->progressBar->show();
|
||||||
|
ui->cancelButton->show();
|
||||||
|
|
||||||
|
switch(action)
|
||||||
|
{
|
||||||
|
case Qt::CopyAction:
|
||||||
|
emit copy(src, dst);
|
||||||
|
break;
|
||||||
|
case Qt::MoveAction:
|
||||||
|
emit move(src, dst);
|
||||||
|
break;
|
||||||
|
case Qt::LinkAction:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox::StandardButton FileManager::overwrite(const QString &dst)
|
||||||
|
{
|
||||||
|
QMessageBox::StandardButton button = QMessageBox::question(this, tr("Overwrite file?"), tr("Destination file %1 already exists. Overwrite?").arg(dst),
|
||||||
|
QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel);
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::errorMessage(const QString &title, const QString &text)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, title, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
QCache<QString, ImageInfoData>* DirFileSystemModel::getCacheInstance()
|
QCache<QString, ImageInfoData>* DirFileSystemModel::getCacheInstance()
|
||||||
@@ -220,7 +518,8 @@ QCache<QString, ImageInfoData>* DirFileSystemModel::getCacheInstance()
|
|||||||
return &cache;
|
return &cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirFileSystemModel::DirFileSystemModel(QObject *parent) : QFileSystemModel(parent)
|
DirFileSystemModel::DirFileSystemModel(QWidget *parentWidget) : QFileSystemModel(parentWidget)
|
||||||
|
,_parentWidget(parentWidget)
|
||||||
{
|
{
|
||||||
_cache = getCacheInstance();
|
_cache = getCacheInstance();
|
||||||
setFilter(QDir::AllEntries | QDir::NoDot);
|
setFilter(QDir::AllEntries | QDir::NoDot);
|
||||||
@@ -251,7 +550,9 @@ const QStringList &DirFileSystemModel::FITSKeywords() const
|
|||||||
|
|
||||||
Qt::ItemFlags DirFileSystemModel::flags(const QModelIndex &index) const
|
Qt::ItemFlags DirFileSystemModel::flags(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
return QFileSystemModel::flags(index) & ~Qt::ItemIsEditable;
|
Qt::ItemFlags ret = QFileSystemModel::flags(index) & ~Qt::ItemIsEditable;
|
||||||
|
if(index.row() == 0)ret &= ~Qt::ItemIsDragEnabled;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DirFileSystemModel::columnCount(const QModelIndex &parent) const
|
int DirFileSystemModel::columnCount(const QModelIndex &parent) const
|
||||||
@@ -314,6 +615,21 @@ bool DirFileSystemModel::hasChildren(const QModelIndex &parent) const
|
|||||||
return QFileSystemModel::hasChildren(parent);
|
return QFileSystemModel::hasChildren(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DirFileSystemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(row);
|
||||||
|
Q_UNUSED(column);
|
||||||
|
if(data->hasUrls())
|
||||||
|
{
|
||||||
|
QStringList srcPaths;
|
||||||
|
for(auto &url : data->urls())
|
||||||
|
srcPaths.append(url.toLocalFile());
|
||||||
|
emit filesAction(action, srcPaths, filePath(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void DirFileSystemModel::loadFitsKeywords(bool enable)
|
void DirFileSystemModel::loadFitsKeywords(bool enable)
|
||||||
{
|
{
|
||||||
_loadFitsKeywords = enable;
|
_loadFitsKeywords = enable;
|
||||||
@@ -322,15 +638,13 @@ void DirFileSystemModel::loadFitsKeywords(bool enable)
|
|||||||
DirView::DirView(QWidget *parent) : QTreeView(parent)
|
DirView::DirView(QWidget *parent) : QTreeView(parent)
|
||||||
{
|
{
|
||||||
_dirFileSystemModel = new DirFileSystemModel(this);
|
_dirFileSystemModel = new DirFileSystemModel(this);
|
||||||
#ifdef Q_OS_WIN64
|
_dirFileSystemModel->setRootPath(QDir::drives().first().path());
|
||||||
_dirFileSystemModel->setRootPath("C:/");
|
|
||||||
#else
|
|
||||||
_dirFileSystemModel->setRootPath("/");
|
|
||||||
#endif
|
|
||||||
_dirFileSystemModel->setReadOnly(false);
|
_dirFileSystemModel->setReadOnly(false);
|
||||||
setDragEnabled(true);
|
setDragEnabled(true);
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
connect(_dirFileSystemModel, &DirFileSystemModel::filesAction, this, &DirView::filesAction);
|
||||||
|
|
||||||
setModel(_dirFileSystemModel);
|
setModel(_dirFileSystemModel);
|
||||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
|
||||||
@@ -356,10 +670,30 @@ DirView::DirView(QWidget *parent) : QTreeView(parent)
|
|||||||
void DirView::setDir(const QString &path)
|
void DirView::setDir(const QString &path)
|
||||||
{
|
{
|
||||||
QString oldPath = _dirFileSystemModel->dir();
|
QString oldPath = _dirFileSystemModel->dir();
|
||||||
_dirFileSystemModel->setDir(path);
|
#ifdef Q_OS_WINDOWS
|
||||||
setRootIndex(_dirFileSystemModel->index(path, 0));
|
const int ROOT_LEN = 3;
|
||||||
|
#else
|
||||||
|
const int ROOT_LEN = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(oldPath.left(ROOT_LEN) != path.left(ROOT_LEN))
|
||||||
|
_dirFileSystemModel->setRootPath(path.left(ROOT_LEN));
|
||||||
|
|
||||||
|
QString newPath = path;
|
||||||
|
if(!QFileInfo::exists(path))
|
||||||
|
{
|
||||||
|
QDir dir(path);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
dir.setPath(QDir::cleanPath(dir.filePath("..")));
|
||||||
|
}while(!dir.exists() && !dir.isRoot());
|
||||||
|
newPath = dir.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
_dirFileSystemModel->setDir(newPath);
|
||||||
|
setRootIndex(_dirFileSystemModel->index(newPath, 0));
|
||||||
clearSelection();
|
clearSelection();
|
||||||
if(oldPath != path)emit dirChanged(path);
|
if(oldPath != newPath)emit dirChanged(newPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DirView::dir() const
|
QString DirView::dir() const
|
||||||
@@ -409,3 +743,24 @@ void DirView::loadFitsKeywords(bool enable)
|
|||||||
{
|
{
|
||||||
_dirFileSystemModel->loadFitsKeywords(enable);
|
_dirFileSystemModel->loadFitsKeywords(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DirView::copySelectedFilesPathsToClipboard() const
|
||||||
|
{
|
||||||
|
QList<QUrl> urls;
|
||||||
|
QString text;
|
||||||
|
auto selected = selectionModel()->selectedRows();
|
||||||
|
for(auto &item : selected)
|
||||||
|
{
|
||||||
|
if(item.column() == 0)
|
||||||
|
{
|
||||||
|
QString path = _dirFileSystemModel->filePath(item);
|
||||||
|
text.append(path); text.append('\n');
|
||||||
|
urls.append(QUrl::fromLocalFile(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
QMimeData *mimeData = new QMimeData();
|
||||||
|
mimeData->setUrls(urls);
|
||||||
|
mimeData->setText(text);
|
||||||
|
clipboard->setMimeData(mimeData);
|
||||||
|
}
|
||||||
|
|||||||
+52
-8
@@ -8,6 +8,7 @@
|
|||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QTabBar>
|
#include <QTabBar>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#include <QMessageBox>
|
||||||
#include "imageinfodata.h"
|
#include "imageinfodata.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@@ -15,6 +16,34 @@ class FileManager;
|
|||||||
class FITSKeyword;
|
class FITSKeyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FileManager;
|
||||||
|
|
||||||
|
class FileTransfer: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FileTransfer(FileManager *fm);
|
||||||
|
~FileTransfer();
|
||||||
|
public slots:
|
||||||
|
void copy(const QStringList &src, const QString &dst);
|
||||||
|
void move(const QStringList &src, const QString &dst);
|
||||||
|
void cancel();
|
||||||
|
signals:
|
||||||
|
void progress(int percent);
|
||||||
|
void finished();
|
||||||
|
void error(const QString &title, const QString &text);
|
||||||
|
private:
|
||||||
|
void perform(const QStringList &src, const QString &dst, bool copy);
|
||||||
|
struct Action
|
||||||
|
{
|
||||||
|
QString src;
|
||||||
|
QString dst;
|
||||||
|
bool dir = false;
|
||||||
|
};
|
||||||
|
FileManager *_fm;
|
||||||
|
bool _run = true;
|
||||||
|
};
|
||||||
|
|
||||||
class PathTabBar : public QTabBar
|
class PathTabBar : public QTabBar
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -29,6 +58,7 @@ signals:
|
|||||||
void tabChanged(const QString &path);
|
void tabChanged(const QString &path);
|
||||||
private:
|
private:
|
||||||
QStringList _tabs;
|
QStringList _tabs;
|
||||||
|
QString tabName(const QString &path);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FITSSelection : public QDialog
|
class FITSSelection : public QDialog
|
||||||
@@ -50,26 +80,28 @@ public:
|
|||||||
~FileManager();
|
~FileManager();
|
||||||
public slots:
|
public slots:
|
||||||
void selectFITSKeywords();
|
void selectFITSKeywords();
|
||||||
protected slots:
|
void copySelectedFilesPaths();
|
||||||
void addTab();
|
void pathEdited();
|
||||||
|
void copyMoveFiles(Qt::DropAction action, const QStringList &src, const QString &dst);
|
||||||
|
QMessageBox::StandardButton overwrite(const QString &dst);
|
||||||
|
void errorMessage(const QString &title, const QString &text);
|
||||||
signals:
|
signals:
|
||||||
void openFile(const QString &path);
|
void openFile(const QString &path);
|
||||||
|
void copy(const QStringList &src, const QString &dst);
|
||||||
|
void move(const QStringList &src, const QString &dst);
|
||||||
private:
|
private:
|
||||||
Ui::FileManager *ui;
|
Ui::FileManager *ui;
|
||||||
PathTabBar *_leftTabBar;
|
PathTabBar *_leftTabBar;
|
||||||
PathTabBar *_rightTabBar;
|
PathTabBar *_rightTabBar;
|
||||||
|
QThread *_thread;
|
||||||
|
FileTransfer *_fileTransfer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirFileSystemModel : public QFileSystemModel
|
class DirFileSystemModel : public QFileSystemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
mutable QCache<QString, ImageInfoData> *_cache = nullptr;
|
|
||||||
static QCache<QString, ImageInfoData>* getCacheInstance();
|
|
||||||
QModelIndex _dir;
|
|
||||||
QStringList _fitsKeywords;
|
|
||||||
bool _loadFitsKeywords = true;
|
|
||||||
public:
|
public:
|
||||||
explicit DirFileSystemModel(QObject *parent = nullptr);
|
explicit DirFileSystemModel(QWidget *parentWidget);
|
||||||
void setDir(const QString &path);
|
void setDir(const QString &path);
|
||||||
QString dir() const;
|
QString dir() const;
|
||||||
void setFITSKeywords(const QStringList &keywords);
|
void setFITSKeywords(const QStringList &keywords);
|
||||||
@@ -79,8 +111,18 @@ public:
|
|||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
bool hasChildren(const QModelIndex &parent) const override;
|
bool hasChildren(const QModelIndex &parent) const override;
|
||||||
|
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
|
||||||
public slots:
|
public slots:
|
||||||
void loadFitsKeywords(bool enable);
|
void loadFitsKeywords(bool enable);
|
||||||
|
signals:
|
||||||
|
void filesAction(Qt::DropAction action, const QStringList &src, const QString &dst);
|
||||||
|
private:
|
||||||
|
mutable QCache<QString, ImageInfoData> *_cache = nullptr;
|
||||||
|
static QCache<QString, ImageInfoData>* getCacheInstance();
|
||||||
|
QModelIndex _dir;
|
||||||
|
QStringList _fitsKeywords;
|
||||||
|
bool _loadFitsKeywords = true;
|
||||||
|
QWidget *_parentWidget = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirView : public QTreeView
|
class DirView : public QTreeView
|
||||||
@@ -98,9 +140,11 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void headerContextMenu(const QPoint &pos);
|
void headerContextMenu(const QPoint &pos);
|
||||||
void loadFitsKeywords(bool enable);
|
void loadFitsKeywords(bool enable);
|
||||||
|
void copySelectedFilesPathsToClipboard() const;
|
||||||
signals:
|
signals:
|
||||||
void dirChanged(const QString &path);
|
void dirChanged(const QString &path);
|
||||||
void openFile(const QString &path);
|
void openFile(const QString &path);
|
||||||
|
void filesAction(Qt::DropAction action, const QStringList &src, const QString &dst);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILEMANAGER_H
|
#endif // FILEMANAGER_H
|
||||||
|
|||||||
+45
-13
@@ -14,32 +14,52 @@
|
|||||||
<string>File Manager</string>
|
<string>File Manager</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="QWidget" name="centralwidget">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="leftLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="leftPath">
|
<layout class="QVBoxLayout" name="leftLayout">
|
||||||
<property name="readOnly">
|
<item>
|
||||||
<bool>true</bool>
|
<widget class="QLineEdit" name="leftPath"/>
|
||||||
</property>
|
</item>
|
||||||
</widget>
|
<item>
|
||||||
|
<widget class="DirView" name="leftTab"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="DirView" name="leftTab"/>
|
<layout class="QVBoxLayout" name="rightLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="rightPath"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="DirView" name="rightTab"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="rightLayout">
|
<layout class="QHBoxLayout" name="progressLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="rightPath">
|
<widget class="QProgressBar" name="progressBar">
|
||||||
<property name="readOnly">
|
<property name="sizePolicy">
|
||||||
<bool>true</bool>
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="DirView" name="rightTab"/>
|
<widget class="QPushButton" name="cancelButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
@@ -60,6 +80,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<addaction name="actionLoad_FITS_keywordsLeft"/>
|
<addaction name="actionLoad_FITS_keywordsLeft"/>
|
||||||
<addaction name="actionSelect_columnsLeft"/>
|
<addaction name="actionSelect_columnsLeft"/>
|
||||||
|
<addaction name="actionCopySelectedFilesPathsLeft"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuRight_Tab">
|
<widget class="QMenu" name="menuRight_Tab">
|
||||||
@@ -68,6 +89,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<addaction name="actionLoad_FITS_keywordsRight"/>
|
<addaction name="actionLoad_FITS_keywordsRight"/>
|
||||||
<addaction name="actionSelect_columnsRight"/>
|
<addaction name="actionSelect_columnsRight"/>
|
||||||
|
<addaction name="actionCopySelectedFilesPathsRight"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuLeft_Tab"/>
|
<addaction name="menuLeft_Tab"/>
|
||||||
@@ -105,6 +127,16 @@
|
|||||||
<string>Select columns</string>
|
<string>Select columns</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionCopySelectedFilesPathsLeft">
|
||||||
|
<property name="text">
|
||||||
|
<string>Copy selected files paths</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCopySelectedFilesPathsRight">
|
||||||
|
<property name="text">
|
||||||
|
<string>Copy selected files paths</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>FITSKeyword</class>
|
||||||
|
<widget class="QDialog" name="FITSKeyword">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>432</width>
|
||||||
|
<height>443</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>FITS Columns</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="keywordList">
|
||||||
|
<property name="dragEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragDropMode">
|
||||||
|
<enum>QAbstractItemView::InternalMove</enum>
|
||||||
|
</property>
|
||||||
|
<property name="defaultDropAction">
|
||||||
|
<enum>Qt::MoveAction</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="keyword"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="removeButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>FITSKeyword</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>215</x>
|
||||||
|
<y>420</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>215</x>
|
||||||
|
<y>221</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>FITSKeyword</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>215</x>
|
||||||
|
<y>420</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>215</x>
|
||||||
|
<y>221</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
@@ -453,7 +453,8 @@ SkyGrid WCSDataT::prepareGrid(uint32_t w, uint32_t h, Database *database)
|
|||||||
|
|
||||||
if(database)
|
if(database)
|
||||||
{
|
{
|
||||||
skyGrid.objects = database->getObjects(minRa, maxRa, minDec, maxDec);
|
double size = std::max(maxRa - minRa, maxDec - minDec);
|
||||||
|
skyGrid.objects = database->getObjects(minRa - size, maxRa + size, minDec - size, maxDec + size);
|
||||||
for(auto &object : skyGrid.objects)
|
for(auto &object : skyGrid.objects)
|
||||||
{
|
{
|
||||||
QPointF p;
|
QPointF p;
|
||||||
|
|||||||
+5
-1
@@ -193,7 +193,11 @@ void ConvertRunable::run()
|
|||||||
QFileInfo info(m_outfile);
|
QFileInfo info(m_outfile);
|
||||||
info.dir().mkpath(".");
|
info.dir().mkpath(".");
|
||||||
|
|
||||||
if(m_params.autostretch)
|
if(m_params.stretch)
|
||||||
|
{
|
||||||
|
rawimage->applySTF(m_params.mtf);
|
||||||
|
}
|
||||||
|
else if(m_params.autostretch)
|
||||||
{
|
{
|
||||||
rawimage->calcStats();
|
rawimage->calcStats();
|
||||||
MTFParam mtfParam = rawimage->calcMTFParams();
|
MTFParam mtfParam = rawimage->calcMTFParams();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <QSemaphore>
|
#include <QSemaphore>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include "imageinfodata.h"
|
#include "imageinfodata.h"
|
||||||
|
#include "mtfparam.h"
|
||||||
|
|
||||||
class Image;
|
class Image;
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ public:
|
|||||||
QSize resize;
|
QSize resize;
|
||||||
Qt::AspectRatioMode aspect = Qt::KeepAspectRatio;
|
Qt::AspectRatioMode aspect = Qt::KeepAspectRatio;
|
||||||
bool autostretch = false;
|
bool autostretch = false;
|
||||||
|
bool stretch = false;
|
||||||
|
MTFParam mtf;
|
||||||
ConvertParams(){}
|
ConvertParams(){}
|
||||||
ConvertParams(const QVariantMap &map);
|
ConvertParams(const QVariantMap &map);
|
||||||
};
|
};
|
||||||
|
|||||||
+14
-2
@@ -3,6 +3,7 @@
|
|||||||
#include <QSurfaceFormat>
|
#include <QSurfaceFormat>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
|
#include <QSettings>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "../thumbnailer/genthumbnail.h"
|
#include "../thumbnailer/genthumbnail.h"
|
||||||
|
|
||||||
@@ -76,8 +77,19 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
QTranslator translator;
|
QTranslator translator;
|
||||||
QTranslator translator2;
|
QTranslator translator2;
|
||||||
if(translator.load(QLocale(), "tenmon", "_", ":/translations"))
|
QSettings settings;
|
||||||
a.installTranslator(&translator);
|
QString lang = settings.value("settings/lang").toString();
|
||||||
|
if(lang.isEmpty())
|
||||||
|
{
|
||||||
|
if(translator.load(QLocale(), "tenmon", "_", ":/translations"))
|
||||||
|
a.installTranslator(&translator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(translator.load("tenmon_" + lang, ":/translations"))
|
||||||
|
a.installTranslator(&translator);
|
||||||
|
}
|
||||||
|
|
||||||
if(translator2.load(QLocale(), "tenmon", "_", a.applicationDirPath()))
|
if(translator2.load(QLocale(), "tenmon", "_", a.applicationDirPath()))
|
||||||
a.installTranslator(&translator2);
|
a.installTranslator(&translator2);
|
||||||
|
|
||||||
|
|||||||
+31
-18
@@ -18,6 +18,7 @@
|
|||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
#include <QStatusBar>
|
#include <QStatusBar>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
#include <QImageWriter>
|
||||||
#include <QMimeDatabase>
|
#include <QMimeDatabase>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
@@ -57,12 +58,18 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
for(auto format : supportedFormats)
|
for(auto format : supportedFormats)
|
||||||
{
|
{
|
||||||
QMimeType mimeType = db.mimeTypeForName(format);
|
QMimeType mimeType = db.mimeTypeForName(format);
|
||||||
_saveFilter.append(mimeType.filterString() + ";;");
|
|
||||||
_openFilter.append("*.");
|
_openFilter.append("*.");
|
||||||
_openFilter.append(mimeType.suffixes().join(" *."));
|
_openFilter.append(mimeType.suffixes().join(" *."));
|
||||||
_openFilter.append(" ");
|
_openFilter.append(" ");
|
||||||
nameFilter.append(mimeType.suffixes());
|
nameFilter.append(mimeType.suffixes());
|
||||||
}
|
}
|
||||||
|
auto supportedWrite = QImageWriter::supportedMimeTypes();
|
||||||
|
for(auto format : supportedWrite)
|
||||||
|
{
|
||||||
|
QMimeType mimeType = db.mimeTypeForName(format);
|
||||||
|
_saveFilter.append(mimeType.filterString() + ";;");
|
||||||
|
}
|
||||||
|
|
||||||
_openFilter.append("*.fit *.fits *.fts *.fz *.xisf *.cr2 *.cr3 *.nef *.dng)");
|
_openFilter.append("*.fit *.fits *.fts *.fz *.xisf *.cr2 *.cr3 *.nef *.dng)");
|
||||||
_openFilter.append(tr(";;All files (*)"));
|
_openFilter.append(tr(";;All files (*)"));
|
||||||
nameFilter.append({"fit", "fits", "fts", "fz", "xisf", "cr2", "cr3", "nef", "dng"});
|
nameFilter.append({"fit", "fits", "fts", "fz", "xisf", "cr2", "cr3", "nef", "dng"});
|
||||||
@@ -148,8 +155,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
databaseViewDock->hide();
|
databaseViewDock->hide();
|
||||||
addDockWidget(Qt::BottomDockWidgetArea, databaseViewDock);
|
addDockWidget(Qt::BottomDockWidgetArea, databaseViewDock);
|
||||||
|
|
||||||
|
QDockWidget *filetreeDock = nullptr;
|
||||||
#if !defined(FLATPAK) || !defined(__aarch64__)
|
#if !defined(FLATPAK) || !defined(__aarch64__)
|
||||||
QDockWidget *filetreeDock = new QDockWidget(tr("File tree"), this);
|
filetreeDock = new QDockWidget(tr("File tree"), this);
|
||||||
filetreeDock->setWidget(m_filetree);
|
filetreeDock->setWidget(m_filetree);
|
||||||
filetreeDock->setObjectName("filetreeDock");
|
filetreeDock->setObjectName("filetreeDock");
|
||||||
databaseViewDock->hide();
|
databaseViewDock->hide();
|
||||||
@@ -322,7 +330,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
dockMenu->addAction(navigationToolbar->toggleViewAction());
|
dockMenu->addAction(navigationToolbar->toggleViewAction());
|
||||||
dockMenu->addAction(filesystemDock->toggleViewAction());
|
dockMenu->addAction(filesystemDock->toggleViewAction());
|
||||||
dockMenu->addAction(databaseViewDock->toggleViewAction());
|
dockMenu->addAction(databaseViewDock->toggleViewAction());
|
||||||
dockMenu->addAction(filetreeDock->toggleViewAction());
|
if(filetreeDock)dockMenu->addAction(filetreeDock->toggleViewAction());
|
||||||
dockMenu->addAction(histogramDock->toggleViewAction());
|
dockMenu->addAction(histogramDock->toggleViewAction());
|
||||||
#ifdef PLATESOLVER
|
#ifdef PLATESOLVER
|
||||||
dockMenu->addAction(_plateSolving->toggleViewAction());
|
dockMenu->addAction(_plateSolving->toggleViewAction());
|
||||||
@@ -373,7 +381,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
infoDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
infoDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
filesystemDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
filesystemDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
databaseViewDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
databaseViewDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
filetreeDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
if(filetreeDock)filetreeDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
if(_plateSolving)_plateSolving->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
if(_plateSolving)_plateSolving->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
m_stretchPanel->setFloatable(false);
|
m_stretchPanel->setFloatable(false);
|
||||||
}
|
}
|
||||||
@@ -612,12 +620,16 @@ void MainWindow::reindex()
|
|||||||
void MainWindow::saveAs()
|
void MainWindow::saveAs()
|
||||||
{
|
{
|
||||||
QString selectedFilter;
|
QString selectedFilter;
|
||||||
|
ImagePtr ptr = m_ringList->currentImage();
|
||||||
|
if(!ptr)return;
|
||||||
|
|
||||||
|
QFileInfo srcFile(ptr->name());
|
||||||
QString file = QFileDialog::getSaveFileName(this,
|
QString file = QFileDialog::getSaveFileName(this,
|
||||||
tr("Save as"),
|
tr("Save as"),
|
||||||
_lastDir,
|
_lastDir + "/" + srcFile.baseName(),
|
||||||
_saveFilter,
|
_saveFilter,
|
||||||
&selectedFilter);
|
&selectedFilter);
|
||||||
auto filterToFormat = [](const QString &file, const QString &filter) -> const char*
|
auto filterToFormat = [](const QString &file, const QString &filter) -> const QString
|
||||||
{
|
{
|
||||||
QString suffix = QFileInfo(file).suffix();
|
QString suffix = QFileInfo(file).suffix();
|
||||||
if(!suffix.compare("jpg", Qt::CaseInsensitive) || !suffix.compare("jpeg", Qt::CaseInsensitive))return "jpeg";
|
if(!suffix.compare("jpg", Qt::CaseInsensitive) || !suffix.compare("jpeg", Qt::CaseInsensitive))return "jpeg";
|
||||||
@@ -627,30 +639,31 @@ void MainWindow::saveAs()
|
|||||||
if(filter.contains("png"))return "png";
|
if(filter.contains("png"))return "png";
|
||||||
if(filter.contains("fits"))return "fits";
|
if(filter.contains("fits"))return "fits";
|
||||||
if(filter.contains("xisf"))return "xisf";
|
if(filter.contains("xisf"))return "xisf";
|
||||||
|
QRegularExpression suf("\\(\\*\\.([a-zA-Z]+).*\\)");
|
||||||
|
auto match = suf.match(filter);
|
||||||
|
if(match.hasMatch())
|
||||||
|
return match.captured(1);
|
||||||
return "jpeg";
|
return "jpeg";
|
||||||
};
|
};
|
||||||
|
|
||||||
if(!file.isEmpty())
|
if(!file.isEmpty())
|
||||||
{
|
{
|
||||||
|
auto button = QMessageBox::question(this, tr("Apply stretch?"), tr("Apply current stretch function to image?"));
|
||||||
|
|
||||||
QString format = filterToFormat(file, selectedFilter);
|
QString format = filterToFormat(file, selectedFilter);
|
||||||
|
|
||||||
if(format == "fits" || format == "xisf")
|
convert(file, format, button == QMessageBox::Yes);
|
||||||
{
|
|
||||||
convert(file, format);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QImage img = m_image->renderToImage();
|
|
||||||
if(!img.isNull())
|
|
||||||
img.save(file, filterToFormat(file, selectedFilter));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::convert(const QString &outfile, const QString &format)
|
void MainWindow::convert(const QString &outfile, const QString &format, bool stretch)
|
||||||
{
|
{
|
||||||
QString file = m_ringList->currentImage()->name();
|
QString file = m_ringList->currentImage()->name();
|
||||||
QThreadPool::globalInstance()->start(new ConvertRunable(file, outfile, format));
|
ConvertRunable::ConvertParams param;
|
||||||
|
param.stretch = stretch;
|
||||||
|
param.mtf = m_stretchPanel->params();
|
||||||
|
|
||||||
|
QThreadPool::globalInstance()->start(new ConvertRunable(file, outfile, format, param));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::markImage()
|
void MainWindow::markImage()
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ public slots:
|
|||||||
void indexDir(const QString &dir);
|
void indexDir(const QString &dir);
|
||||||
void reindex();
|
void reindex();
|
||||||
void saveAs();
|
void saveAs();
|
||||||
void convert(const QString &outfile, const QString &format);
|
void convert(const QString &outfile, const QString &format, bool stretch);
|
||||||
void markImage();
|
void markImage();
|
||||||
void unmarkImage();
|
void unmarkImage();
|
||||||
void markAndNext();
|
void markAndNext();
|
||||||
|
|||||||
+22
-6
@@ -1195,12 +1195,28 @@ void RawImage::applySTF(const MTFParam &mtfParams)
|
|||||||
for(size_t i = 0; i < len; i++)
|
for(size_t i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
float x;
|
float x;
|
||||||
if constexpr(std::numeric_limits<std::remove_reference_t<decltype(*src)>>::is_integer)x = src[i] * iscale;
|
if(m_ch == 4)
|
||||||
else x = src[i] * unit.first + unit.second;
|
{
|
||||||
x = (x - mtfParams.blackPoint[0]) / (mtfParams.whitePoint[0] - mtfParams.blackPoint[0]);
|
size_t c = i & 0x3;
|
||||||
x = std::clamp(x, 0.0f, 1.0f);
|
if(c < 3)
|
||||||
x = ((mtfParams.midPoint[0] - 1.0f) * x) / ((2.0f * mtfParams.midPoint[0] - 1.0f) * x - mtfParams.midPoint[0]);
|
{
|
||||||
src[i] = x * s;
|
if constexpr(std::numeric_limits<std::remove_reference_t<decltype(*src)>>::is_integer)x = src[i] * iscale;
|
||||||
|
else x = src[i] * unit.first + unit.second;
|
||||||
|
x = (x - mtfParams.blackPoint[c]) / (mtfParams.whitePoint[c] - mtfParams.blackPoint[c]);
|
||||||
|
x = std::clamp(x, 0.0f, 1.0f);
|
||||||
|
x = ((mtfParams.midPoint[c] - 1.0f) * x) / ((2.0f * mtfParams.midPoint[c] - 1.0f) * x - mtfParams.midPoint[c]);
|
||||||
|
src[i] = x * s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if constexpr(std::numeric_limits<std::remove_reference_t<decltype(*src)>>::is_integer)x = src[i] * iscale;
|
||||||
|
else x = src[i] * unit.first + unit.second;
|
||||||
|
x = (x - mtfParams.blackPoint[0]) / (mtfParams.whitePoint[0] - mtfParams.blackPoint[0]);
|
||||||
|
x = std::clamp(x, 0.0f, 1.0f);
|
||||||
|
x = ((mtfParams.midPoint[0] - 1.0f) * x) / ((2.0f * mtfParams.midPoint[0] - 1.0f) * x - mtfParams.midPoint[0]);
|
||||||
|
src[i] = x * s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+99
-14
@@ -4,6 +4,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
|
#include <QJSValueIterator>
|
||||||
#include "loadrunable.h"
|
#include "loadrunable.h"
|
||||||
#include "rawimage.h"
|
#include "rawimage.h"
|
||||||
#include "loadimage.h"
|
#include "loadimage.h"
|
||||||
@@ -40,7 +41,7 @@ ScriptEngine::ScriptEngine(Database *database, BatchProcessing *parent)
|
|||||||
void ScriptEngine::setParams(const QString &scriptPath, const QList<QPair<QString, QString>> &paths, const QString &outputDir)
|
void ScriptEngine::setParams(const QString &scriptPath, const QList<QPair<QString, QString>> &paths, const QString &outputDir)
|
||||||
{
|
{
|
||||||
_scriptPath = scriptPath;
|
_scriptPath = scriptPath;
|
||||||
_paths = paths;
|
setPaths(paths);
|
||||||
_outputDir = outputDir + "/";
|
_outputDir = outputDir + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,14 +418,73 @@ QJSValue ScriptEngine::newArray(uint size)
|
|||||||
return _jsEngine->newArray(size);
|
return _jsEngine->newArray(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::run()
|
QJSValue ScriptEngine::eval(const QString &program)
|
||||||
{
|
{
|
||||||
QJSValue jsPaths = _jsEngine->newArray(_paths.size());
|
QStringList stackTrace;
|
||||||
for(qsizetype i=0; i<_paths.size(); i++)
|
QJSValue result = _jsEngine->evaluate(program, QString(), 1, &stackTrace);
|
||||||
jsPaths.setProperty(i, _jsEngine->newQObject(new File(_paths[i].first, _paths[i].second, this)));
|
|
||||||
|
if(result.isError())
|
||||||
|
{
|
||||||
|
QString error = result.property("name").toString() + " on line " + result.property("lineNumber").toString() + " : " + result.toString();
|
||||||
|
error += "\n" + result.property("stack").toString();
|
||||||
|
emit newMessage(error, true);
|
||||||
|
}
|
||||||
|
else if(!result.isUndefined())
|
||||||
|
{
|
||||||
|
emit newMessage(result.toString(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList ScriptEngine::complete(const QString &line)
|
||||||
|
{
|
||||||
|
QStringList complete;
|
||||||
|
|
||||||
|
QJSValue globObj = _jsEngine->globalObject();
|
||||||
|
|
||||||
|
QRegularExpression reg("[a-zA-Z_][a-zA-Z0-9_]*");
|
||||||
|
auto match = reg.match(line);
|
||||||
|
if(match.hasMatch())
|
||||||
|
{
|
||||||
|
QString var = match.captured();
|
||||||
|
if(globObj.hasProperty(var))
|
||||||
|
{
|
||||||
|
complete.clear();
|
||||||
|
QJSValueIterator it(globObj.property(var));
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
if(it.name() != "constructor" && it.name() != "objectNameChanged")
|
||||||
|
complete.append(var + "." + it.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QJSValueIterator it(globObj);
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
complete.append(it.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::setPaths(const QList<QPair<QString, QString> > &paths)
|
||||||
|
{
|
||||||
|
_paths = paths;
|
||||||
|
QJSValue jsPaths = _jsEngine->newArray(paths.size());
|
||||||
|
for(qsizetype i=0; i<paths.size(); i++)
|
||||||
|
jsPaths.setProperty(i, _jsEngine->newQObject(new File(paths[i].first, paths[i].second, this)));
|
||||||
|
|
||||||
_jsEngine->globalObject().setProperty("files", jsPaths);
|
_jsEngine->globalObject().setProperty("files", jsPaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::run()
|
||||||
|
{
|
||||||
QFile scriptFile(_scriptPath);
|
QFile scriptFile(_scriptPath);
|
||||||
if(!scriptFile.open(QIODevice::ReadOnly))
|
if(!scriptFile.open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
@@ -608,7 +668,7 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
|
|||||||
_fitsKeywordsLoaded = false;
|
_fitsKeywordsLoaded = false;
|
||||||
_fitsKeywords.clear();
|
_fitsKeywords.clear();
|
||||||
|
|
||||||
if(QRegularExpression("(fits?|fz|fts)", QRegularExpression::CaseInsensitiveOption).match(suffix()).hasMatch())
|
if(isFITS(suffix()))
|
||||||
{
|
{
|
||||||
fitsfile *file;
|
fitsfile *file;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
@@ -625,16 +685,22 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
|
|||||||
int naxis;
|
int naxis;
|
||||||
long naxes[3] = {0};
|
long naxes[3] = {0};
|
||||||
int type = -1;
|
int type = -1;
|
||||||
|
std::vector<int> imageIdxs;
|
||||||
for(int i=1; i <= num; i++)
|
for(int i=1; i <= num; i++)
|
||||||
{
|
{
|
||||||
fits_movabs_hdu(file, i, IMAGE_HDU, &status);
|
fits_movabs_hdu(file, i, IMAGE_HDU, &status);
|
||||||
fits_get_hdu_type(file, &type, &status);
|
fits_get_hdu_type(file, &type, &status);
|
||||||
fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);
|
if(type == IMAGE_HDU)
|
||||||
if(type == IMAGE_HDU && naxis >= 2 && naxis <= 3 && status == 0)
|
{
|
||||||
break;
|
fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);
|
||||||
if(i == num)return false;
|
if(naxis >= 2 && naxis <= 3)imageIdxs.push_back(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(modify->_imageIdx >= imageIdxs.size())return false;
|
||||||
|
fits_movabs_hdu(file, imageIdxs[modify->_imageIdx], &type, &status);
|
||||||
|
fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);
|
||||||
|
|
||||||
for(auto &remove : modify->_remove)
|
for(auto &remove : modify->_remove)
|
||||||
{
|
{
|
||||||
int status = 0;//we ignore errors from here
|
int status = 0;//we ignore errors from here
|
||||||
@@ -731,7 +797,7 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
|
|||||||
|
|
||||||
return status == 0;
|
return status == 0;
|
||||||
}
|
}
|
||||||
else if(suffix().toLower() == "xisf")
|
else if(isXISF(suffix()))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -742,13 +808,16 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
|
|||||||
qDebug() << "modify" << in << out;
|
qDebug() << "modify" << in << out;
|
||||||
|
|
||||||
for(auto &remove : modify->_remove)
|
for(auto &remove : modify->_remove)
|
||||||
modifyXISF.removeFITSKeyword(0, remove.toStdString());
|
modifyXISF.removeFITSKeyword(modify->_imageIdx, remove.toStdString());
|
||||||
|
|
||||||
for(auto &record : modify->_update)
|
for(auto &record : modify->_update)
|
||||||
modifyXISF.updateFITSKeyword(0, {record.key.toStdString(), record.value.toString().toStdString(), record.comment.toStdString()}, true);
|
modifyXISF.updateFITSKeyword(modify->_imageIdx, {record.key.toStdString(), record.value.toString().toStdString(), record.comment.toStdString()}, true);
|
||||||
|
|
||||||
for(auto &record : modify->_add)
|
for(auto &record : modify->_add)
|
||||||
modifyXISF.addFITSKeyword(0, {record.key.toStdString(), record.value.toString().toStdString(), record.comment.toStdString()});
|
modifyXISF.addFITSKeyword(modify->_imageIdx, {record.key.toStdString(), record.value.toString().toStdString(), record.comment.toStdString()});
|
||||||
|
|
||||||
|
for(auto &property : modify->_property)
|
||||||
|
modifyXISF.updateProperty(modify->_imageIdx, property);
|
||||||
|
|
||||||
modifyXISF.save(out.toLocal8Bit().toStdString());
|
modifyXISF.save(out.toLocal8Bit().toStdString());
|
||||||
modifyXISF.close();
|
modifyXISF.close();
|
||||||
@@ -757,6 +826,7 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
|
|||||||
}
|
}
|
||||||
catch(std::filesystem::filesystem_error &err)
|
catch(std::filesystem::filesystem_error &err)
|
||||||
{
|
{
|
||||||
|
if(_engine)_engine->newMessage("Failed to modify file " + _path + " " + err.what(), true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch(LibXISF::Error &err)
|
catch(LibXISF::Error &err)
|
||||||
@@ -926,6 +996,21 @@ void FITSRecordModify::addKeyword(const QString &key, const QVariant &value, con
|
|||||||
_update.append({key.toLatin1(), value, comment.toLatin1()});
|
_update.append({key.toLatin1(), value, comment.toLatin1()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FITSRecordModify::updateProperty(const QString &id, const LibXISF::Variant &value)
|
||||||
|
{
|
||||||
|
_property.append(LibXISF::Property(id.toStdString(), value));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FITSRecordModify::imageIndex() const
|
||||||
|
{
|
||||||
|
return _imageIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FITSRecordModify::setImageIndex(uint32_t idx)
|
||||||
|
{
|
||||||
|
_imageIdx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
bool TextFile::open(const QString &path, const QString &mode)
|
bool TextFile::open(const QString &path, const QString &mode)
|
||||||
{
|
{
|
||||||
_fr.setFileName(path);
|
_fr.setFileName(path);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <QSemaphore>
|
#include <QSemaphore>
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "imageinfodata.h"
|
#include "imageinfodata.h"
|
||||||
|
#include "libxisf.h"
|
||||||
|
|
||||||
class BatchProcessing;
|
class BatchProcessing;
|
||||||
class Solver;
|
class Solver;
|
||||||
@@ -63,6 +64,9 @@ public:
|
|||||||
#endif // PLATESOLVER
|
#endif // PLATESOLVER
|
||||||
QJSValue newObject();
|
QJSValue newObject();
|
||||||
QJSValue newArray(uint size);
|
QJSValue newArray(uint size);
|
||||||
|
QJSValue eval(const QString &program);
|
||||||
|
QStringList complete(const QString &line);
|
||||||
|
void setPaths(const QList<QPair<QString, QString>> &paths);
|
||||||
public slots:
|
public slots:
|
||||||
void run();
|
void run();
|
||||||
signals:
|
signals:
|
||||||
@@ -140,6 +144,8 @@ class FITSRecordModify : public QObject
|
|||||||
QStringList _remove;
|
QStringList _remove;
|
||||||
QVector<FITSRecord> _update;
|
QVector<FITSRecord> _update;
|
||||||
QVector<FITSRecord> _add;
|
QVector<FITSRecord> _add;
|
||||||
|
QVector<LibXISF::Property> _property;
|
||||||
|
uint32_t _imageIdx = 0;
|
||||||
|
|
||||||
friend class File;
|
friend class File;
|
||||||
public:
|
public:
|
||||||
@@ -147,6 +153,10 @@ public:
|
|||||||
Q_INVOKABLE void removeKeyword(const QString &key);
|
Q_INVOKABLE void removeKeyword(const QString &key);
|
||||||
Q_INVOKABLE void updateKeyword(const QString &key, const QVariant &value, const QString &comment = QString());
|
Q_INVOKABLE void updateKeyword(const QString &key, const QVariant &value, const QString &comment = QString());
|
||||||
Q_INVOKABLE void addKeyword(const QString &key, const QVariant &value, const QString &comment = QString());
|
Q_INVOKABLE void addKeyword(const QString &key, const QVariant &value, const QString &comment = QString());
|
||||||
|
Q_PROPERTY(uint32_t imageIndex READ imageIndex WRITE setImageIndex);
|
||||||
|
void updateProperty(const QString &id, const LibXISF::Variant &value);
|
||||||
|
uint32_t imageIndex() const;
|
||||||
|
void setImageIndex(uint32_t idx);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextFile : public QObject
|
class TextFile : public QObject
|
||||||
|
|||||||
+29
-1
@@ -129,11 +129,30 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent)
|
|||||||
delete item;
|
delete item;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_lang = new QComboBox(this);
|
||||||
|
m_lang->addItems({"English", "Français", "Slovenčina", "Português"});
|
||||||
|
QString lang;
|
||||||
|
switch(QLocale().language())
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case QLocale::English: lang = "en"; break;
|
||||||
|
case QLocale::French: lang = "fr"; break;
|
||||||
|
case QLocale::Slovak: lang = "sk"; break;
|
||||||
|
case QLocale::Portuguese: lang = "pt_BR"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lang = settings.value("settings/lang", lang).toString();
|
||||||
|
if(lang == "en")m_lang->setCurrentIndex(0);
|
||||||
|
else if(lang == "fr")m_lang->setCurrentIndex(1);
|
||||||
|
else if(lang == "sk")m_lang->setCurrentIndex(2);
|
||||||
|
else if(lang == "pt_BR")m_lang->setCurrentIndex(3);
|
||||||
|
|
||||||
layout->addRow(tr("Image preload count"), m_preloadImages);
|
layout->addRow(tr("Image preload count"), m_preloadImages);
|
||||||
layout->addRow(tr("Thumbnails size"), m_thumSize);
|
layout->addRow(tr("Thumbnails size"), m_thumSize);
|
||||||
layout->addRow(tr("Saturation"), m_saturation);
|
layout->addRow(tr("Saturation"), m_saturation);
|
||||||
layout->addRow(tr("Slideshow interval"), m_slideShowTime);
|
layout->addRow(tr("Slideshow interval"), m_slideShowTime);
|
||||||
layout->addRow(tr("Image interpolation"), m_filtering);
|
layout->addRow(tr("Image interpolation"), m_filtering);
|
||||||
|
layout->addRow(tr("Language"), m_lang);
|
||||||
layout->addRow(m_qualityThumbnail);
|
layout->addRow(m_qualityThumbnail);
|
||||||
layout->addRow(m_useNativeDialog);
|
layout->addRow(m_useNativeDialog);
|
||||||
layout->addRow(m_bestFit);
|
layout->addRow(m_bestFit);
|
||||||
@@ -150,7 +169,6 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent)
|
|||||||
#endif
|
#endif
|
||||||
//layout->addRow(new QLabel(tr("Changes in settings will take effect after program restart.")));
|
//layout->addRow(new QLabel(tr("Changes in settings will take effect after program restart.")));
|
||||||
|
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
|
||||||
buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
@@ -237,4 +255,14 @@ void SettingsDialog::saveSettings()
|
|||||||
}
|
}
|
||||||
settings.setValue("settings/headerhighlightkeywords", headerHighlight.keys());
|
settings.setValue("settings/headerhighlightkeywords", headerHighlight.keys());
|
||||||
settings.setValue("settings/headerhighlightcolors", colors);
|
settings.setValue("settings/headerhighlightcolors", colors);
|
||||||
|
QString lang;
|
||||||
|
int langIdx = m_lang->currentIndex();
|
||||||
|
switch(langIdx)
|
||||||
|
{
|
||||||
|
case 0: lang = "en"; break;
|
||||||
|
case 1: lang = "fr"; break;
|
||||||
|
case 2: lang = "sk"; break;
|
||||||
|
case 3: lang = "pt_BR"; break;
|
||||||
|
}
|
||||||
|
settings.setValue("settings/lang", lang);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ private:
|
|||||||
QListWidget *m_headerHighlight;
|
QListWidget *m_headerHighlight;
|
||||||
QColor m_color = Qt::yellow;
|
QColor m_color = Qt::yellow;
|
||||||
QLineEdit *m_keyword;
|
QLineEdit *m_keyword;
|
||||||
|
QComboBox *m_lang;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SETTINGSDIALOG_H
|
#endif // SETTINGSDIALOG_H
|
||||||
|
|||||||
@@ -186,6 +186,19 @@ bool Solver::updateHeader(QString &error)
|
|||||||
modify.updateKeyword("CTYPE2", "DEC--TAN", QByteArray("first parameter DEC, projection TANgential"));
|
modify.updateKeyword("CTYPE2", "DEC--TAN", QByteArray("first parameter DEC, projection TANgential"));
|
||||||
modify.updateKeyword("RADESYS", "ICRS", QByteArray("International Celestial Reference System"));
|
modify.updateKeyword("RADESYS", "ICRS", QByteArray("International Celestial Reference System"));
|
||||||
modify.updateKeyword("EQUINOX", 2000, QByteArray("Equinox of coordinates"));
|
modify.updateKeyword("EQUINOX", 2000, QByteArray("Equinox of coordinates"));
|
||||||
|
|
||||||
|
LibXISF::F64Matrix matrix(2, 2);
|
||||||
|
matrix(0, 0) = std::cos(rotationRad) * cdeltx;
|
||||||
|
matrix(0, 1) =-std::sin(rotationRad) * cdelty;
|
||||||
|
matrix(1, 0) = std::sin(rotationRad) * cdeltx;
|
||||||
|
matrix(1, 1) = std::cos(rotationRad) * cdelty;
|
||||||
|
|
||||||
|
modify.updateProperty("PCL:AstrometricSolution:ReferenceCelestialCoordinates", LibXISF::F64Vector({solution.ra, solution.dec}));
|
||||||
|
modify.updateProperty("PCL:AstrometricSolution:ReferenceImageCoordinates", LibXISF::F64Vector({_stats.width / 2.0, _stats.height / 2.0}));
|
||||||
|
modify.updateProperty("PCL:AstrometricSolution:LinearTransformationMatrix", LibXISF::F64Matrix(matrix));
|
||||||
|
modify.updateProperty("PCL:AstrometricSolution:ProjectionSystem", LibXISF::String("Gnomonic"));
|
||||||
|
modify.updateProperty("PCL:AstrometricSolution:ReferenceNativeCoordinates", LibXISF::F64Vector({0, 90}));
|
||||||
|
|
||||||
bool ret = file.modifyFITSRecords(&modify);
|
bool ret = file.modifyFITSRecords(&modify);
|
||||||
if(!ret)error = tr("Failed to update file header");
|
if(!ret)error = tr("Failed to update file header");
|
||||||
else emit headerUpdated(_path);
|
else emit headerUpdated(_path);
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ StretchToolbar::~StretchToolbar()
|
|||||||
settings.setValue("stretchtoolbar/autostretch", m_autoStretchOnLoad->isChecked());
|
settings.setValue("stretchtoolbar/autostretch", m_autoStretchOnLoad->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MTFParam &StretchToolbar::params() const
|
||||||
|
{
|
||||||
|
return m_mtfParam;
|
||||||
|
}
|
||||||
|
|
||||||
void StretchToolbar::stretchImage(Image *img)
|
void StretchToolbar::stretchImage(Image *img)
|
||||||
{
|
{
|
||||||
if(img && img->rawImage())
|
if(img && img->rawImage())
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class StretchToolbar : public QToolBar
|
|||||||
public:
|
public:
|
||||||
explicit StretchToolbar(QWidget *parent = nullptr);
|
explicit StretchToolbar(QWidget *parent = nullptr);
|
||||||
~StretchToolbar();
|
~StretchToolbar();
|
||||||
|
const MTFParam& params() const;
|
||||||
public slots:
|
public slots:
|
||||||
void stretchImage(Image *img);
|
void stretchImage(Image *img);
|
||||||
void resetMTF();
|
void resetMTF();
|
||||||
|
|||||||
Binary file not shown.
+428
-444
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+428
-444
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+428
-444
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+428
-444
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user