summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2019-02-02 21:23:52 +0100
committerGravatar Robert C. Helling <helling@atdotde.de>2019-02-07 16:06:43 +0100
commit8a8063c1cd7b8e5eae861a8d7eeb89e7e3251e03 (patch)
tree261d1a78d4c21378e08380def3775823b82fe079
parent07b0df215f5562657a3a2c9dd20a95d489e8dcd3 (diff)
downloadsubsurface-8a8063c1cd7b8e5eae861a8d7eeb89e7e3251e03.tar.gz
Profile: add "synchronous" mode for picture plotting
The thumbnails were fetched in the background to achieve a snappier UI. The problem with that is that on LaTeX etc. export only placeholder thumbnails were shown. Therefore, implement a synchronous mode. This only tries to fetch cached thumbnails or calculate thumbnails for images. Videos and remote files are not supported. Fixes #1963 Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
-rw-r--r--core/imagedownloader.cpp17
-rw-r--r--core/imagedownloader.h10
-rw-r--r--desktop-widgets/divelogexportdialog.cpp2
-rw-r--r--profile-widget/profilewidget2.cpp19
-rw-r--r--profile-widget/profilewidget2.h5
-rw-r--r--qt-models/divepicturemodel.cpp2
6 files changed, 40 insertions, 15 deletions
diff --git a/core/imagedownloader.cpp b/core/imagedownloader.cpp
index d78409a3c..1559b129b 100644
--- a/core/imagedownloader.cpp
+++ b/core/imagedownloader.cpp
@@ -456,8 +456,23 @@ void Thumbnailer::imageDownloadFailed(QString filename)
workingOn.remove(filename);
}
-QImage Thumbnailer::fetchThumbnail(const QString &filename)
+QImage Thumbnailer::fetchThumbnail(const QString &filename, bool synchronous)
{
+ if (synchronous) {
+ // In synchronous mode, first try the thumbnail cache.
+ Thumbnail thumbnail = getThumbnailFromCache(filename);
+ if (!thumbnail.img.isNull())
+ return thumbnail.img;
+
+ // If that didn't work, try to thumbnail the image.
+ thumbnail = getHashedImage(filename, false);
+ if (thumbnail.type == MEDIATYPE_STILL_LOADING || thumbnail.img.isNull())
+ return failImage; // No support for delayed thumbnails (web).
+
+ int size = maxThumbnailSize();
+ return thumbnail.img.scaled(size, size, Qt::KeepAspectRatio);
+ }
+
QMutexLocker l(&lock);
// We are not currently fetching this thumbnail - add it to the list.
diff --git a/core/imagedownloader.h b/core/imagedownloader.h
index e0d70f59f..280383250 100644
--- a/core/imagedownloader.h
+++ b/core/imagedownloader.h
@@ -31,9 +31,13 @@ public:
static Thumbnailer *instance();
// Schedule a thumbnail for fetching or calculation.
- // Returns a placeholder thumbnail. The actual thumbnail will be sent
- // via a signal later.
- QImage fetchThumbnail(const QString &filename);
+ // If synchronous is false, returns a placeholder thumbnail.
+ // The actual thumbnail will be sent via a signal later.
+ // If synchronous is true, try to fetch the actual thumbnail.
+ // In this mode only precalculated thumbnails or thumbnails
+ // from pictures are returned. Video extraction and remote
+ // images are not supported.
+ QImage fetchThumbnail(const QString &filename, bool synchronous);
// Schedule multiple thumbnails for forced recalculation
void calculateThumbnails(const QVector<QString> &filenames);
diff --git a/desktop-widgets/divelogexportdialog.cpp b/desktop-widgets/divelogexportdialog.cpp
index 37fb8cee4..04f0b03de 100644
--- a/desktop-widgets/divelogexportdialog.cpp
+++ b/desktop-widgets/divelogexportdialog.cpp
@@ -254,7 +254,7 @@ void DiveLogExportDialog::exportProfile(const QString filename, const bool selec
void DiveLogExportDialog::saveProfile(const struct dive *dive, const QString filename)
{
ProfileWidget2 *profile = MainWindow::instance()->graphics;
- profile->plotDive(dive, true);
+ profile->plotDive(dive, true, false, true);
profile->setToolTipVisibile(false);
QPixmap pix = profile->grab();
profile->setToolTipVisibile(true);
diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp
index 3a9fd0c5f..85109875f 100644
--- a/profile-widget/profilewidget2.cpp
+++ b/profile-widget/profilewidget2.cpp
@@ -165,7 +165,7 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent),
addActionShortcut(Qt::Key_Right, &ProfileWidget2::keyRightAction);
connect(Thumbnailer::instance(), &Thumbnailer::thumbnailChanged, this, &ProfileWidget2::updateThumbnail, Qt::QueuedConnection);
- connect(DivePictureModel::instance(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(plotPictures()));
+ connect(DivePictureModel::instance(), &DivePictureModel::rowsInserted, this, &ProfileWidget2::plotPictures);
connect(DivePictureModel::instance(), &DivePictureModel::picturesRemoved, this, &ProfileWidget2::removePictures);
connect(DivePictureModel::instance(), &DivePictureModel::modelReset, this, &ProfileWidget2::plotPictures);
#endif // SUBSURFACE_MOBILE
@@ -548,7 +548,7 @@ void ProfileWidget2::resetZoom()
}
// Currently just one dive, but the plan is to enable All of the selected dives.
-void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPictures)
+void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPictures, bool plotPicturesSynchronously)
{
static bool firstCall = true;
#ifndef SUBSURFACE_MOBILE
@@ -827,7 +827,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
if (doClearPictures)
clearPictures();
else
- plotPictures();
+ plotPicturesInternal(plotPicturesSynchronously);
toolTipItem->refresh(mapToScene(mapFromGlobal(QCursor::pos())));
#endif
@@ -2153,7 +2153,7 @@ void ProfileWidget2::updateThumbnail(QString filename, QImage thumbnail, duratio
}
// Create a PictureEntry object and add its thumbnail to the scene if profile pictures are shown.
-ProfileWidget2::PictureEntry::PictureEntry(offset_t offsetIn, const QString &filenameIn, QGraphicsScene *scene) : offset(offsetIn),
+ProfileWidget2::PictureEntry::PictureEntry(offset_t offsetIn, const QString &filenameIn, QGraphicsScene *scene, bool synchronous) : offset(offsetIn),
duration(duration_t {0}),
filename(filenameIn),
thumbnail(new DivePictureItem)
@@ -2161,7 +2161,7 @@ ProfileWidget2::PictureEntry::PictureEntry(offset_t offsetIn, const QString &fil
int size = Thumbnailer::defaultThumbnailSize();
scene->addItem(thumbnail.get());
thumbnail->setVisible(prefs.show_pictures_in_profile);
- QImage img = Thumbnailer::instance()->fetchThumbnail(filename).scaled(size, size, Qt::KeepAspectRatio);
+ QImage img = Thumbnailer::instance()->fetchThumbnail(filename, synchronous).scaled(size, size, Qt::KeepAspectRatio);
thumbnail->setPixmap(QPixmap::fromImage(img));
thumbnail->setFileUrl(filename);
}
@@ -2228,6 +2228,11 @@ void ProfileWidget2::updateThumbnailXPos(PictureEntry &e)
// This function resets the picture thumbnails of the current dive.
void ProfileWidget2::plotPictures()
{
+ plotPicturesInternal(false);
+}
+
+void ProfileWidget2::plotPicturesInternal(bool synchronous)
+{
pictures.clear();
if (currentState == ADD || currentState == PLAN)
return;
@@ -2238,7 +2243,7 @@ void ProfileWidget2::plotPictures()
// Note that FOR_EACH_PICTURE handles current_dive being null gracefully.
FOR_EACH_PICTURE(current_dive) {
if (picture->offset.seconds > 0 && picture->offset.seconds <= current_dive->duration.seconds)
- pictures.emplace_back(picture->offset, QString(picture->filename), scene());
+ pictures.emplace_back(picture->offset, QString(picture->filename), scene(), synchronous);
}
if (pictures.empty())
return;
@@ -2346,7 +2351,7 @@ void ProfileWidget2::dropEvent(QDropEvent *event)
// The parameters are passed directly to the contructor.
// The call returns an iterator to the new element (which might differ from
// the old iterator, since the buffer might have been reallocated).
- newPos = pictures.emplace(newPos, offset, filename, scene());
+ newPos = pictures.emplace(newPos, offset, filename, scene(), false);
updateThumbnailXPos(*newPos);
calculatePictureYPositions();
}
diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h
index 679abcf1d..300e46e39 100644
--- a/profile-widget/profilewidget2.h
+++ b/profile-widget/profilewidget2.h
@@ -75,7 +75,7 @@ public:
ProfileWidget2(QWidget *parent = 0);
void resetZoom();
void scale(qreal sx, qreal sy);
- void plotDive(const struct dive *d = 0, bool force = false, bool clearPictures = false);
+ void plotDive(const struct dive *d = 0, bool force = false, bool clearPictures = false, bool plotPicturesSynchronously = false);
void setupItem(AbstractProfilePolygonItem *item, DiveCartesianAxis *vAxis, int vData, int hData, int zValue);
void setPrintMode(bool mode, bool grayscale = false);
bool getPrintMode();
@@ -173,6 +173,7 @@ private: /*methods*/
void createPPGas(PartialPressureGasItem *item, int verticalColumn, color_index_t color, color_index_t colorAlert,
const double *thresholdSettingsMin, const double *thresholdSettingsMax);
void clearPictures();
+ void plotPicturesInternal(bool synchronous);
private:
DivePlotDataModel *dataModel;
int zoomLevel;
@@ -240,7 +241,7 @@ private:
std::unique_ptr<DivePictureItem> thumbnail;
// For videos with known duration, we represent the duration of the video by a line
std::unique_ptr<QGraphicsRectItem> durationLine;
- PictureEntry (offset_t offsetIn, const QString &filenameIn, QGraphicsScene *scene);
+ PictureEntry (offset_t offsetIn, const QString &filenameIn, QGraphicsScene *scene, bool synchronous);
bool operator< (const PictureEntry &e) const;
};
void updateThumbnailXPos(PictureEntry &e);
diff --git a/qt-models/divepicturemodel.cpp b/qt-models/divepicturemodel.cpp
index 4db81d546..babd404f5 100644
--- a/qt-models/divepicturemodel.cpp
+++ b/qt-models/divepicturemodel.cpp
@@ -42,7 +42,7 @@ void DivePictureModel::updateThumbnails()
{
updateZoom();
for (PictureEntry &entry: pictures)
- entry.image = Thumbnailer::instance()->fetchThumbnail(entry.filename);
+ entry.image = Thumbnailer::instance()->fetchThumbnail(entry.filename, false);
}
void DivePictureModel::updateDivePictures()