Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package tenmon for openSUSE:Factory checked in at 2026-02-06 19:10:23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/tenmon (Old) and /work/SRC/openSUSE:Factory/.tenmon.new.1670 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "tenmon" Fri Feb 6 19:10:23 2026 rev:10 rq:1331541 version:20260119 Changes: -------- --- /work/SRC/openSUSE:Factory/tenmon/tenmon.changes 2025-10-21 11:17:00.132260037 +0200 +++ /work/SRC/openSUSE:Factory/.tenmon.new.1670/tenmon.changes 2026-02-06 19:16:57.048781634 +0100 @@ -1,0 +2,11 @@ +Fri Feb 6 08:39:42 UTC 2026 - Paolo Stivanin <[email protected]> + +- Update to 20260119: + * Try to fix crash in ImageRingList + * Fix compile error + * Clean up code + * Update metainfo + * Open parent directory if it doesn't exist + * Fix copy/move operation + +------------------------------------------------------------------- Old: ---- tenmon-20250915.tar.gz New: ---- tenmon-20260119.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ tenmon.spec ++++++ --- /var/tmp/diff_new_pack.prAiRe/_old 2026-02-06 19:16:57.820814299 +0100 +++ /var/tmp/diff_new_pack.prAiRe/_new 2026-02-06 19:16:57.824814468 +0100 @@ -1,7 +1,7 @@ # # spec file for package tenmon # -# Copyright (c) 2025 SUSE LLC and contributors +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -21,7 +21,7 @@ %endif Name: tenmon -Version: 20250915 +Version: 20260119 Release: 0 Summary: FITS and XISF image viewer, converter and indexer License: GPL-3.0-or-later @@ -32,7 +32,7 @@ # PATCH-FIX-UPSTREAM Patch1: fix-libxisf-include.patch BuildRequires: gcc%{?force_gcc_version}-c++ >= 12 -BuildRequires: libXISF-devel >= 0.2.13+git3.556bb22 +BuildRequires: libXISF-devel >= 0.2.13+git5.7b70b6a BuildRequires: libzstd-devel BuildRequires: pkgconfig BuildRequires: qt6-base-devel >= 6.2.0 ++++++ fix-libxisf-include.patch ++++++ --- /var/tmp/diff_new_pack.prAiRe/_old 2026-02-06 19:16:57.872816500 +0100 +++ /var/tmp/diff_new_pack.prAiRe/_new 2026-02-06 19:16:57.880816837 +0100 @@ -2,8 +2,8 @@ =================================================================== --- tenmon.orig/src/main.cpp +++ tenmon/src/main.cpp -@@ -5,6 +5,7 @@ - #include <QCommandLineParser> +@@ -6,6 +6,7 @@ + #include <QSettings> #include <stdlib.h> #include "../thumbnailer/genthumbnail.h" +#include <libxisf.h> ++++++ tenmon-20250915.tar.gz -> tenmon-20260119.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/space.nouspiro.tenmon.metainfo.xml new/tenmon/space.nouspiro.tenmon.metainfo.xml --- old/tenmon/space.nouspiro.tenmon.metainfo.xml 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/space.nouspiro.tenmon.metainfo.xml 2026-01-19 20:57:13.000000000 +0100 @@ -59,6 +59,15 @@ </screenshots> <content_rating type="oars-1.1"/> <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> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/batchprocessing.cpp new/tenmon/src/batchprocessing.cpp --- old/tenmon/src/batchprocessing.cpp 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/batchprocessing.cpp 2026-01-19 20:57:13.000000000 +0100 @@ -113,12 +113,8 @@ _engine = new Script::ScriptEngine(_database, this); connect(_engine, &Script::ScriptEngine::newMessage, this, &BatchProcessing::newMessage); - QStringList apiList; - apiList << "core.log" << "core.mark" << "core.unmark" << "core.isMarked" << "core.getObjects" << "core.setMaxthread"; - apiList << "core.sync" << "core.getString" << "core.getInt" << "core.getFloat" << "core.question" << "core.plot"; - apiList << "fileName" << "absoluteFileName"; + _completerModel = new QStringListModel(this); - _completerModel->setStringList(apiList); _completer = new QCompleter(_completerModel, this); _ui->consoleLineEdit->setCompleter(_completer); connect(_ui->executeButton, &QPushButton::clicked, _ui->consoleLineEdit, &QLineEdit::returnPressed); @@ -128,13 +124,13 @@ QString program = _ui->consoleLineEdit->text(); QJSValue val = _engine->eval(program); _ui->consoleLineEdit->addLine(); - qDebug() << val.toString(); + //qDebug() << val.toString(); } }); connect(_ui->consoleLineEdit, &QLineEdit::textEdited, [this](const QString &text){ QStringList comp = _engine->complete(text); - qDebug() << comp; + //qDebug() << comp; _completerModel->setStringList(comp); }); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/imageringlist.cpp new/tenmon/src/imageringlist.cpp --- old/tenmon/src/imageringlist.cpp 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/imageringlist.cpp 2026-01-19 20:57:13.000000000 +0100 @@ -111,7 +111,7 @@ emit thumbnailLoaded(this); } -ImageRingList::ImageRingList(Database *database, const QStringList &nameFilter, QObject *parent) : QAbstractItemModel(parent) +ImageRingList::ImageRingList(Database *database, const QStringList &nameFilter, QObject *parent) : QAbstractListModel(parent) , m_liveMode(false) , m_analyzeLevel(None) , m_database(database) @@ -412,7 +412,7 @@ img->clearThumbnail(); } -QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const +/*QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const { Q_UNUSED(parent); return createIndex(row, column, m_images.at(row).get()); @@ -422,7 +422,7 @@ { Q_UNUSED(child); return QModelIndex(); -} +}*/ int ImageRingList::rowCount(const QModelIndex &parent) const { @@ -432,31 +432,35 @@ return 0; } -int ImageRingList::columnCount(const QModelIndex &parent) const +/*int ImageRingList::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 1; -} +}*/ QVariant ImageRingList::data(const QModelIndex &index, int role) const { - switch(role) - { - case Qt::DisplayRole: + if(index.isValid() && index.row() >= 0 && index.row() < m_images.size()) { - QFileInfo info(m_images.at(index.row())->name()); - return info.fileName(); - } - case Qt::FontRole: - { - bool marked = m_database->isMarked(m_images.at(index.row())->name()); - QFont font; - font.setBold(marked); - return font; - } - default: - return QVariant(); + switch(role) + { + case Qt::DisplayRole: + { + QFileInfo info(m_images.at(index.row())->name()); + return info.fileName(); + } + case Qt::FontRole: + { + bool marked = m_database->isMarked(m_images.at(index.row())->name()); + QFont font; + font.setBold(marked); + return font; + } + default: + return QVariant(); + } } + return QVariant(); } QVariant ImageRingList::headerData(int section, Qt::Orientation orientation, int role) const diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/imageringlist.h new/tenmon/src/imageringlist.h --- old/tenmon/src/imageringlist.h 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/imageringlist.h 2026-01-19 20:57:13.000000000 +0100 @@ -51,7 +51,7 @@ class Database; -class ImageRingList : public QAbstractItemModel +class ImageRingList : public QAbstractListModel { Q_OBJECT int m_width; @@ -93,10 +93,10 @@ void updateMark(); void clearThumbnails(); - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &child) const override; + //QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + //QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; + //int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; public slots: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/loadrunable.cpp new/tenmon/src/loadrunable.cpp --- old/tenmon/src/loadrunable.cpp 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/loadrunable.cpp 2026-01-19 20:57:13.000000000 +0100 @@ -193,7 +193,11 @@ QFileInfo info(m_outfile); info.dir().mkpath("."); - if(m_params.autostretch) + if(m_params.stretch) + { + rawimage->applySTF(m_params.mtf); + } + else if(m_params.autostretch) { rawimage->calcStats(); MTFParam mtfParam = rawimage->calcMTFParams(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/loadrunable.h new/tenmon/src/loadrunable.h --- old/tenmon/src/loadrunable.h 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/loadrunable.h 2026-01-19 20:57:13.000000000 +0100 @@ -6,6 +6,7 @@ #include <QSemaphore> #include <QSize> #include "imageinfodata.h" +#include "mtfparam.h" class Image; @@ -33,6 +34,8 @@ QSize resize; Qt::AspectRatioMode aspect = Qt::KeepAspectRatio; bool autostretch = false; + bool stretch = false; + MTFParam mtf; ConvertParams(){} ConvertParams(const QVariantMap &map); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/main.cpp new/tenmon/src/main.cpp --- old/tenmon/src/main.cpp 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/main.cpp 2026-01-19 20:57:13.000000000 +0100 @@ -3,6 +3,7 @@ #include <QSurfaceFormat> #include <QTranslator> #include <QCommandLineParser> +#include <QSettings> #include <stdlib.h> #include "../thumbnailer/genthumbnail.h" @@ -76,8 +77,19 @@ QTranslator translator; QTranslator translator2; - if(translator.load(QLocale(), "tenmon", "_", ":/translations")) - a.installTranslator(&translator); + QSettings settings; + 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())) a.installTranslator(&translator2); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/mainwindow.cpp new/tenmon/src/mainwindow.cpp --- old/tenmon/src/mainwindow.cpp 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/mainwindow.cpp 2026-01-19 20:57:13.000000000 +0100 @@ -18,6 +18,7 @@ #include <QThreadPool> #include <QStatusBar> #include <QImageReader> +#include <QImageWriter> #include <QMimeDatabase> #include <QDesktopServices> #include <QJsonDocument> @@ -57,12 +58,18 @@ for(auto format : supportedFormats) { QMimeType mimeType = db.mimeTypeForName(format); - _saveFilter.append(mimeType.filterString() + ";;"); _openFilter.append("*."); _openFilter.append(mimeType.suffixes().join(" *.")); _openFilter.append(" "); 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(tr(";;All files (*)")); nameFilter.append({"fit", "fits", "fts", "fz", "xisf", "cr2", "cr3", "nef", "dng"}); @@ -613,12 +620,16 @@ void MainWindow::saveAs() { QString selectedFilter; + ImagePtr ptr = m_ringList->currentImage(); + if(!ptr)return; + + QFileInfo srcFile(ptr->name()); QString file = QFileDialog::getSaveFileName(this, tr("Save as"), - _lastDir, + _lastDir + "/" + srcFile.baseName(), _saveFilter, &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(); if(!suffix.compare("jpg", Qt::CaseInsensitive) || !suffix.compare("jpeg", Qt::CaseInsensitive))return "jpeg"; @@ -628,30 +639,31 @@ if(filter.contains("png"))return "png"; if(filter.contains("fits"))return "fits"; 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"; }; if(!file.isEmpty()) { + auto button = QMessageBox::question(this, tr("Apply stretch?"), tr("Apply current stretch function to image?")); + QString format = filterToFormat(file, selectedFilter); - if(format == "fits" || format == "xisf") - { - convert(file, format); - } - else - { - QImage img = m_image->renderToImage(); - if(!img.isNull()) - img.save(file, filterToFormat(file, selectedFilter)); - } + convert(file, format, button == QMessageBox::Yes); } } -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(); - 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() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/mainwindow.h new/tenmon/src/mainwindow.h --- old/tenmon/src/mainwindow.h 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/mainwindow.h 2026-01-19 20:57:13.000000000 +0100 @@ -52,7 +52,7 @@ void indexDir(const QString &dir); void reindex(); void saveAs(); - void convert(const QString &outfile, const QString &format); + void convert(const QString &outfile, const QString &format, bool stretch); void markImage(); void unmarkImage(); void markAndNext(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/rawimage.cpp new/tenmon/src/rawimage.cpp --- old/tenmon/src/rawimage.cpp 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/rawimage.cpp 2026-01-19 20:57:13.000000000 +0100 @@ -1195,12 +1195,28 @@ for(size_t i = 0; i < len; i++) { float x; - 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; + if(m_ch == 4) + { + size_t c = i & 0x3; + if(c < 3) + { + 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; + } } }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/settingsdialog.cpp new/tenmon/src/settingsdialog.cpp --- old/tenmon/src/settingsdialog.cpp 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/settingsdialog.cpp 2026-01-19 20:57:13.000000000 +0100 @@ -129,11 +129,30 @@ 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("Thumbnails size"), m_thumSize); layout->addRow(tr("Saturation"), m_saturation); layout->addRow(tr("Slideshow interval"), m_slideShowTime); layout->addRow(tr("Image interpolation"), m_filtering); + layout->addRow(tr("Language"), m_lang); layout->addRow(m_qualityThumbnail); layout->addRow(m_useNativeDialog); layout->addRow(m_bestFit); @@ -150,7 +169,6 @@ #endif //layout->addRow(new QLabel(tr("Changes in settings will take effect after program restart."))); - QDialogButtonBox *buttonBox = new QDialogButtonBox(this); buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); @@ -237,4 +255,14 @@ } settings.setValue("settings/headerhighlightkeywords", headerHighlight.keys()); 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); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/settingsdialog.h new/tenmon/src/settingsdialog.h --- old/tenmon/src/settingsdialog.h 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/settingsdialog.h 2026-01-19 20:57:13.000000000 +0100 @@ -32,6 +32,7 @@ QListWidget *m_headerHighlight; QColor m_color = Qt::yellow; QLineEdit *m_keyword; + QComboBox *m_lang; }; #endif // SETTINGSDIALOG_H diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/stretchtoolbar.cpp new/tenmon/src/stretchtoolbar.cpp --- old/tenmon/src/stretchtoolbar.cpp 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/stretchtoolbar.cpp 2026-01-19 20:57:13.000000000 +0100 @@ -104,6 +104,11 @@ settings.setValue("stretchtoolbar/autostretch", m_autoStretchOnLoad->isChecked()); } +const MTFParam &StretchToolbar::params() const +{ + return m_mtfParam; +} + void StretchToolbar::stretchImage(Image *img) { if(img && img->rawImage()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tenmon/src/stretchtoolbar.h new/tenmon/src/stretchtoolbar.h --- old/tenmon/src/stretchtoolbar.h 2025-09-15 15:55:00.000000000 +0200 +++ new/tenmon/src/stretchtoolbar.h 2026-01-19 20:57:13.000000000 +0100 @@ -22,6 +22,7 @@ public: explicit StretchToolbar(QWidget *parent = nullptr); ~StretchToolbar(); + const MTFParam& params() const; public slots: void stretchImage(Image *img); void resetMTF();
