diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 102ca2ea..260fd513 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -311,13 +311,19 @@ void MainWindow::paintEvent(QPaintEvent *event) } } } - else if (customBackgroundColor.isValid()) - { - painter.fillRect(viewportRect, customBackgroundColor); - } else { - painter.eraseRect(viewportRect); + const QColor &backgroundColor = customBackgroundColor.isValid() ? customBackgroundColor : painter.background().color(); + painter.fillRect(viewportRect, backgroundColor); + + if (getCurrentFileDetails().errorData.has_value()) + { + const QVImageCore::ErrorData &errorData = getCurrentFileDetails().errorData.value(); + const QString errorMessage = tr("Error occurred opening\n%3\n%2 (Error %1)").arg(QString::number(errorData.errorNum), errorData.errorString, getCurrentFileDetails().fileInfo.fileName()); + painter.setFont(font()); + painter.setPen(Qv::getPerceivedBrightness(backgroundColor) > 0.5 ? QColorConstants::Black : QColorConstants::White); + painter.drawText(viewportRect, errorMessage, QTextOption(Qt::AlignCenter)); + } } } } @@ -399,6 +405,9 @@ void MainWindow::fileChanged(const bool isRestoringState) updateWindowFilePath(); if (!isRestoringState) setWindowSize(); + + // full repaint to handle error message + update(); } void MainWindow::zoomLevelChanged() @@ -523,13 +532,15 @@ void MainWindow::buildWindowTitle() QString newString = "qView"; if (getCurrentFileDetails().fileInfo.isFile()) { - auto getFileName = [this]() { return getCurrentFileDetails().fileInfo.fileName(); }; - auto getZoomLevel = [this]() { return QString::number(graphicsView->getZoomLevel() * 100.0, 'f', 1) + "%"; }; - auto getImageIndex = [this]() { return QString::number(getCurrentFileDetails().loadedIndexInFolder+1); }; - auto getImageCount = [this]() { return QString::number(getCurrentFileDetails().folderFileInfoList.count()); }; - auto getImageWidth = [this]() { return QString::number(getCurrentFileDetails().baseImageSize.width()); }; - auto getImageHeight = [this]() { return QString::number(getCurrentFileDetails().baseImageSize.height()); }; - auto getFileSize = [this]() { return QVInfoDialog::formatBytes(getCurrentFileDetails().fileInfo.size()); }; + const QVImageCore::FileDetails &fileDetails = getCurrentFileDetails(); + const bool hasError = fileDetails.errorData.has_value(); + auto getFileName = [&]() { return fileDetails.fileInfo.fileName(); }; + auto getZoomLevel = [&]() { return QString::number((hasError ? 1.0 : graphicsView->getZoomLevel()) * 100.0, 'f', 1) + "%"; }; + auto getImageIndex = [&]() { return QString::number(fileDetails.loadedIndexInFolder+1); }; + auto getImageCount = [&]() { return QString::number(fileDetails.folderFileInfoList.count()); }; + auto getImageWidth = [&]() { return QString::number(hasError ? 0 : fileDetails.baseImageSize.width()); }; + auto getImageHeight = [&]() { return QString::number(hasError ? 0 : fileDetails.baseImageSize.height()); }; + auto getFileSize = [&]() { return QVInfoDialog::formatBytes(hasError ? 0 : fileDetails.fileInfo.size()); }; switch (qvApp->getSettingsManager().getEnum("titlebarmode")) { case Qv::TitleBarText::Minimal: { diff --git a/src/qvgraphicsview.cpp b/src/qvgraphicsview.cpp index 23e668ec..e0611eca 100644 --- a/src/qvgraphicsview.cpp +++ b/src/qvgraphicsview.cpp @@ -37,7 +37,6 @@ QVGraphicsView::QVGraphicsView(QWidget *parent) : QGraphicsView(parent) connect(&imageCore, &QVImageCore::animatedFrameChanged, this, &QVGraphicsView::animatedFrameChanged); connect(&imageCore, &QVImageCore::fileChanged, this, &QVGraphicsView::postLoad); - connect(&imageCore, &QVImageCore::readError, this, &QVGraphicsView::error); expensiveScaleTimer = new QTimer(this); expensiveScaleTimer->setSingleShot(true); @@ -928,16 +927,6 @@ MainWindow* QVGraphicsView::getMainWindow() const return qobject_cast(window()); } -void QVGraphicsView::error(int errorNum, const QString &errorString, const QString &fileName) -{ - if (!errorString.isEmpty()) - { - closeImage(); - QMessageBox::critical(this, tr("Error"), tr("Error occurred opening \"%3\":\n%2 (Error %1)").arg(QString::number(errorNum), errorString, fileName)); - return; - } -} - void QVGraphicsView::settingsUpdated() { auto &settingsManager = qvApp->getSettingsManager(); diff --git a/src/qvgraphicsview.h b/src/qvgraphicsview.h index 6757c93d..af01d9a5 100644 --- a/src/qvgraphicsview.h +++ b/src/qvgraphicsview.h @@ -159,8 +159,6 @@ private slots: void postLoad(); - void error(int errorNum, const QString &errorString, const QString &fileName); - private: QGraphicsPixmapItem *loadedPixmapItem; diff --git a/src/qvimagecore.cpp b/src/qvimagecore.cpp index 658f9dee..ef578ea8 100644 --- a/src/qvimagecore.cpp +++ b/src/qvimagecore.cpp @@ -106,14 +106,14 @@ void QVImageCore::loadFile(const QString &fileName, bool isReloading) else { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - loadFutureWatcher.setFuture(QtConcurrent::run(this, &QVImageCore::readFile, sanitaryFileName, targetColorSpace, false)); + loadFutureWatcher.setFuture(QtConcurrent::run(this, &QVImageCore::readFile, sanitaryFileName, targetColorSpace)); #else - loadFutureWatcher.setFuture(QtConcurrent::run(&QVImageCore::readFile, this, sanitaryFileName, targetColorSpace, false)); + loadFutureWatcher.setFuture(QtConcurrent::run(&QVImageCore::readFile, this, sanitaryFileName, targetColorSpace)); #endif } } -QVImageCore::ReadData QVImageCore::readFile(const QString &fileName, const QColorSpace &targetColorSpace, bool forCache) +QVImageCore::ReadData QVImageCore::readFile(const QString &fileName, const QColorSpace &targetColorSpace) { QImageReader imageReader; imageReader.setDecideFormatFromContent(true); @@ -155,12 +155,16 @@ QVImageCore::ReadData QVImageCore::readFile(const QString &fileName, const QColo fileInfo.absoluteFilePath(), fileInfo.size(), imageReader.size(), - targetColorSpace + targetColorSpace, + {} }; - // Only error out when not loading for cache - if (readPixmap.isNull() && !forCache) + + if (readPixmap.isNull()) { - emit readError(imageReader.error(), imageReader.errorString(), fileInfo.fileName()); + readData.errorData = { + imageReader.error(), + imageReader.errorString() + }; } return readData; @@ -168,6 +172,16 @@ QVImageCore::ReadData QVImageCore::readFile(const QString &fileName, const QColo void QVImageCore::loadPixmap(const ReadData &readData) { + if (readData.errorData.has_value()) + { + currentFileDetails = getEmptyFileDetails(); + currentFileDetails.errorData = readData.errorData; + } + else + { + currentFileDetails.errorData = {}; + } + // Do this first so we can keep folder info even when loading errored files currentFileDetails.fileInfo = QFileInfo(readData.absoluteFilePath); currentFileDetails.updateLoadedIndexInFolder(); @@ -177,8 +191,11 @@ void QVImageCore::loadPixmap(const ReadData &readData) // Reset mechanism to avoid stalling while loading waitingOnLoad = false; - if (readData.pixmap.isNull()) + if (currentFileDetails.errorData.has_value()) + { + loadEmptyPixmap(); return; + } loadedPixmap = readData.pixmap; @@ -223,11 +240,23 @@ void QVImageCore::loadPixmap(const ReadData &readData) } void QVImageCore::closeImage() +{ + currentFileDetails = getEmptyFileDetails(); + loadEmptyPixmap(); +} + +void QVImageCore::loadEmptyPixmap() { loadedPixmap = QPixmap(); loadedMovie.stop(); loadedMovie.setFileName(""); - currentFileDetails = { + + emit fileChanged(); +} + +QVImageCore::FileDetails QVImageCore::getEmptyFileDetails() +{ + return { QFileInfo(), currentFileDetails.folderFileInfoList, currentFileDetails.loadedIndexInFolder, @@ -236,10 +265,9 @@ void QVImageCore::closeImage() false, QSize(), QSize(), - QElapsedTimer() + QElapsedTimer(), + {} }; - - emit fileChanged(); } // All file logic, sorting, etc should be moved to a different class or file @@ -451,9 +479,9 @@ void QVImageCore::requestCachingFile(const QString &filePath, const QColorSpace }); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - cacheFutureWatcher->setFuture(QtConcurrent::run(this, &QVImageCore::readFile, filePath, targetColorSpace, true)); + cacheFutureWatcher->setFuture(QtConcurrent::run(this, &QVImageCore::readFile, filePath, targetColorSpace)); #else - cacheFutureWatcher->setFuture(QtConcurrent::run(&QVImageCore::readFile, this, filePath, targetColorSpace, true)); + cacheFutureWatcher->setFuture(QtConcurrent::run(&QVImageCore::readFile, this, filePath, targetColorSpace)); #endif } diff --git a/src/qvimagecore.h b/src/qvimagecore.h index 2a59e549..4acea5cb 100644 --- a/src/qvimagecore.h +++ b/src/qvimagecore.h @@ -35,6 +35,12 @@ class QVImageCore : public QObject QString mimeType; }; + struct ErrorData + { + int errorNum; + QString errorString; + }; + struct FileDetails { QFileInfo fileInfo; @@ -46,6 +52,7 @@ class QVImageCore : public QObject QSize baseImageSize; QSize loadedPixmapSize; QElapsedTimer timeSinceLoaded; + std::optional errorData; void updateLoadedIndexInFolder(); }; @@ -57,12 +64,13 @@ class QVImageCore : public QObject qint64 fileSize; QSize imageSize; QColorSpace targetColorSpace; + std::optional errorData; }; explicit QVImageCore(QObject *parent = nullptr); void loadFile(const QString &fileName, bool isReloading = false); - ReadData readFile(const QString &fileName, const QColorSpace &targetColorSpace, bool forCache); + ReadData readFile(const QString &fileName, const QColorSpace &targetColorSpace); void loadPixmap(const ReadData &readData); void closeImage(); QList getCompatibleFiles(const QString &dirPath); @@ -94,7 +102,9 @@ class QVImageCore : public QObject void fileChanged(); - void readError(int errorNum, const QString &errorString, const QString &fileName); +protected: + void loadEmptyPixmap(); + FileDetails getEmptyFileDetails(); private: QPixmap loadedPixmap; diff --git a/src/qvnamespace.h b/src/qvnamespace.h index 2b2004ce..ee78aab3 100644 --- a/src/qvnamespace.h +++ b/src/qvnamespace.h @@ -1,6 +1,7 @@ #ifndef QVNAMESPACE_H #define QVNAMESPACE_H +#include #include #include @@ -123,6 +124,11 @@ namespace Qv action == ViewportScrollAction::None || action == ViewportScrollAction::Pan; } + + inline qreal getPerceivedBrightness(const QColor &color) + { + return (color.red() * 0.299 + color.green() * 0.587 + color.blue() * 0.114) / 255.0; + } } #endif // QVNAMESPACE_H