Skip to content

Commit

Permalink
Merge pull request #689 from jdpurcell/nonmodalerrors
Browse files Browse the repository at this point in the history
Non-modal errors via background painting
  • Loading branch information
jurplel authored Jun 25, 2024
2 parents f0d9627 + 0df0c11 commit d296753
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 52 deletions.
57 changes: 49 additions & 8 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ MainWindow::MainWindow(QWidget *parent) :
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_OpaquePaintEvent);

// Initialize variables
justLaunchedWithImage = false;
Expand Down Expand Up @@ -266,6 +267,28 @@ void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
QMainWindow::mouseDoubleClickEvent(event);
}

void MainWindow::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);

QPainter painter(this);

const int viewportY = qMax(getTitlebarOverlap(), graphicsView->mapTo(this, QPoint()).y());
const QRect viewportRect = rect().adjusted(0, viewportY, 0, 0);

const QColor &backgroundColor = customBackgroundColor.isValid() ? customBackgroundColor : painter.background().color();
painter.fillRect(rect(), backgroundColor);

if (getCurrentFileDetails().errorData.hasError && viewportRect.isValid())
{
const QVImageCore::ErrorData &errorData = getCurrentFileDetails().errorData;
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(QVApplication::getPerceivedBrightness(backgroundColor) > 0.5 ? Qt::black : Qt::white);
painter.drawText(viewportRect, errorMessage, QTextOption(Qt::AlignCenter));
}
}

void MainWindow::openFile(const QString &fileName)
{
graphicsView->loadFile(fileName);
Expand All @@ -278,6 +301,9 @@ void MainWindow::settingsUpdated()

buildWindowTitle();

//bgcolor
customBackgroundColor = settingsManager.getBoolean("bgcolorenabled") ? QColor(settingsManager.getString("bgcolor")) : QColor();

// menubarenabled
bool menuBarEnabled = settingsManager.getBoolean("menubarenabled");
#ifdef Q_OS_MACOS
Expand All @@ -300,6 +326,9 @@ void MainWindow::settingsUpdated()
ui->fullscreenLabel->setVisible(qvApp->getSettingsManager().getBoolean("fullscreendetails") && (windowState() == Qt::WindowFullScreen));

setWindowSize();

// repaint in case background color changed
update();
}

void MainWindow::shortcutsUpdated()
Expand Down Expand Up @@ -333,6 +362,9 @@ void MainWindow::fileChanged()
if (info->isVisible())
refreshProperties();
buildWindowTitle();

// repaint to handle error message
update();
}

void MainWindow::disableActions()
Expand Down Expand Up @@ -449,9 +481,12 @@ void MainWindow::buildWindowTitle()
newString = QString::number(getCurrentFileDetails().loadedIndexInFolder+1);
newString += "/" + QString::number(getCurrentFileDetails().folderFileInfoList.count());
newString += " - " + getCurrentFileDetails().fileInfo.fileName();
newString += " - " + QString::number(getCurrentFileDetails().baseImageSize.width());
newString += "x" + QString::number(getCurrentFileDetails().baseImageSize.height());
newString += " - " + QVInfoDialog::formatBytes(getCurrentFileDetails().fileInfo.size());
if (!getCurrentFileDetails().errorData.hasError)
{
newString += " - " + QString::number(getCurrentFileDetails().baseImageSize.width());
newString += "x" + QString::number(getCurrentFileDetails().baseImageSize.height());
newString += " - " + QVInfoDialog::formatBytes(getCurrentFileDetails().fileInfo.size());
}
newString += " - qView";
break;
}
Expand Down Expand Up @@ -511,11 +546,7 @@ void MainWindow::setWindowSize()
if (menuBar()->isVisible())
extraWidgetsSize.rheight() += menuBar()->height();

int titlebarOverlap = 0;
#ifdef COCOA_LOADED
// To account for fullsizecontentview on mac
titlebarOverlap = QVCocoaFunctions::getObscuredHeight(window()->windowHandle());
#endif
const int titlebarOverlap = getTitlebarOverlap();
if (titlebarOverlap != 0)
extraWidgetsSize.rheight() += titlebarOverlap;

Expand Down Expand Up @@ -1135,3 +1166,13 @@ void MainWindow::toggleFullScreen()
showFullScreen();
}
}

int MainWindow::getTitlebarOverlap() const
{
#ifdef COCOA_LOADED
// To account for fullsizecontentview on mac
return QVCocoaFunctions::getObscuredHeight(window()->windowHandle());
#endif

return 0;
}
6 changes: 6 additions & 0 deletions src/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ class MainWindow : public QMainWindow

void toggleFullScreen();

int getTitlebarOverlap() const;

const QVImageCore::FileDetails& getCurrentFileDetails() const { return graphicsView->getCurrentFileDetails(); }

public slots:
Expand Down Expand Up @@ -141,6 +143,8 @@ public slots:

void mouseDoubleClickEvent(QMouseEvent *event) override;

void paintEvent(QPaintEvent *event) override;

protected slots:
void settingsUpdated();
void shortcutsUpdated();
Expand All @@ -158,6 +162,8 @@ protected slots:

QVInfoDialog *info;

QColor customBackgroundColor;

bool justLaunchedWithImage;

Qt::WindowStates storedWindowState;
Expand Down
5 changes: 5 additions & 0 deletions src/qvapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,8 @@ void QVApplication::defineFilterLists()
nameFilterList << filterString;
nameFilterList << tr("All Files") + " (*)";
}

qreal QVApplication::getPerceivedBrightness(const QColor &color)
{
return (color.red() * 0.299 + color.green() * 0.587 + color.blue() * 0.114) / 255.0;
}
2 changes: 2 additions & 0 deletions src/qvapplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class QVApplication : public QApplication

ActionManager &getActionManager() { return actionManager; }

static qreal getPerceivedBrightness(const QColor &color);

private:

QList<MainWindow*> lastActiveWindows;
Expand Down
27 changes: 1 addition & 26 deletions src/qvgraphicsview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ QVGraphicsView::QVGraphicsView(QWidget *parent) : QGraphicsView(parent)
setDragMode(QGraphicsView::ScrollHandDrag);
setFrameShape(QFrame::NoFrame);
setTransformationAnchor(QGraphicsView::NoAnchor);
viewport()->setAutoFillBackground(false);

// part of a pathetic attempt at gesture support
grabGesture(Qt::PinchGesture);
Expand Down Expand Up @@ -53,7 +54,6 @@ QVGraphicsView::QVGraphicsView(QWidget *parent) : QGraphicsView(parent)
connect(&imageCore, &QVImageCore::animatedFrameChanged, this, &QVGraphicsView::animatedFrameChanged);
connect(&imageCore, &QVImageCore::fileChanged, this, &QVGraphicsView::postLoad);
connect(&imageCore, &QVImageCore::updateLoadedPixmapItem, this, &QVGraphicsView::updateLoadedPixmapItem);
connect(&imageCore, &QVImageCore::readError, this, &QVGraphicsView::error);

// Should replace the other timer eventually
expensiveScaleTimerNew = new QTimer(this);
Expand Down Expand Up @@ -681,35 +681,10 @@ void QVGraphicsView::centerOn(const QGraphicsItem *item)
centerOn(item->sceneBoundingRect().center());
}

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();

//bgcolor
QBrush newBrush;
newBrush.setStyle(Qt::SolidPattern);
if (!settingsManager.getBoolean("bgcolorenabled"))
{
newBrush.setColor(QColor(0, 0, 0, 0));
}
else
{
QColor newColor;
newColor.setNamedColor(settingsManager.getString("bgcolor"));
newBrush.setColor(newColor);
}
setBackgroundBrush(newBrush);

//filtering
if (settingsManager.getBoolean("filteringenabled"))
loadedPixmapItem->setTransformationMode(Qt::SmoothTransformation);
Expand Down
2 changes: 0 additions & 2 deletions src/qvgraphicsview.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ private slots:

void updateLoadedPixmapItem();

void error(int errorNum, const QString &errorString, const QString &fileName);

private:


Expand Down
57 changes: 43 additions & 14 deletions src/qvimagecore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,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);
Expand Down Expand Up @@ -164,19 +164,34 @@ 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 = {
true,
imageReader.error(),
imageReader.errorString()
};
}

return readData;
}

void QVImageCore::loadPixmap(const ReadData &readData)
{
if (readData.errorData.hasError)
{
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();
Expand All @@ -186,8 +201,11 @@ void QVImageCore::loadPixmap(const ReadData &readData)
// Reset mechanism to avoid stalling while loading
waitingOnLoad = false;

if (readData.pixmap.isNull())
if (currentFileDetails.errorData.hasError)
{
loadEmptyPixmap();
return;
}

loadedPixmap = matchCurrentRotation(readData.pixmap);

Expand Down Expand Up @@ -232,11 +250,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,
Expand All @@ -245,10 +275,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
Expand Down Expand Up @@ -479,9 +508,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
}

Expand Down
15 changes: 13 additions & 2 deletions src/qvimagecore.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ class QVImageCore : public QObject
QString mimeType;
};

struct ErrorData
{
bool hasError;
int errorNum;
QString errorString;
};

struct FileDetails
{
QFileInfo fileInfo;
Expand All @@ -45,6 +52,7 @@ class QVImageCore : public QObject
QSize baseImageSize;
QSize loadedPixmapSize;
QElapsedTimer timeSinceLoaded;
ErrorData errorData;

void updateLoadedIndexInFolder();
};
Expand All @@ -56,12 +64,13 @@ class QVImageCore : public QObject
qint64 fileSize;
QSize imageSize;
QColorSpace targetColorSpace;
ErrorData 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<CompatibleFile> getCompatibleFiles(const QString &dirPath) const;
Expand Down Expand Up @@ -99,7 +108,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;
Expand Down

0 comments on commit d296753

Please sign in to comment.