<commit_before>#include "viewer/zoom-window.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QMenu>
#include <QMessageBox>
#include <QScrollBar>
#include <QShortcut>
#include <ui_zoom-window.h>
#include "functions.h"
#include "helpers.h"
#include "image-context-menu.h"
#include "mainwindow.h"
#include "models/filename.h"
#include "models/filtering/post-filter.h"
#include "models/page.h"
#include "models/profile.h"
#include "models/site.h"
#include "settings/optionswindow.h"
#include "tag-context-menu.h"
#include "tags/tag-stylist.h"
#include "threads/image-loader.h"
#include "threads/image-loader-queue.h"
#include "ui/QAffiche.h"
#include "viewer/details-window.h"


ZoomWindow::ZoomWindow(QList<QSharedPointer<Image>> images, const QSharedPointer<Image> &image, Site *site, Profile *profile, mainWindow *parent)
	: QWidget(nullptr, Qt::Window), m_parent(parent), m_profile(profile), m_favorites(profile->getFavorites()), m_viewItLater(profile->getKeptForLater()), m_ignore(profile->getIgnored()), m_settings(profile->getSettings()), ui(new Ui::ZoomWindow), m_site(site), m_timeout(300), m_tooBig(false), m_loadedImage(false), m_loadedDetails(false), m_finished(false), m_size(0), m_fullScreen(nullptr), m_isFullscreen(false), m_isSlideshowRunning(false), m_images(std::move(images)), m_displayImage(QPixmap()), m_displayMovie(nullptr), m_labelImageScaled(false)
{
	setAttribute(Qt::WA_DeleteOnClose);
	ui->setupUi(this);

	m_pendingAction = PendingNothing;
	m_pendingClose = false;

	restoreGeometry(m_settings->value("Zoom/geometry").toByteArray());
	ui->buttonPlus->setChecked(m_settings->value("Zoom/plus", false).toBool());
	ui->progressBarDownload->hide();

	QShortcut *escape = new QShortcut(QKeySequence(Qt::Key_Escape), this);
		connect(escape, &QShortcut::activated, this, &ZoomWindow::close);
	QShortcut *save = new QShortcut(QKeySequence::Save, this);
		connect(save, SIGNAL(activated()), this, SLOT(saveImage()));
	QShortcut *saveAs = new QShortcut(QKeySequence::SaveAs, this);
		connect(saveAs, &QShortcut::activated, this, &ZoomWindow::saveImageAs);
	QShortcut *arrowNext = new QShortcut(QKeySequence(Qt::Key_Right), this);
		connect(arrowNext, &QShortcut::activated, this, &ZoomWindow::next);
	QShortcut *arrowPrevious = new QShortcut(QKeySequence(Qt::Key_Left), this);
		connect(arrowPrevious, &QShortcut::activated, this, &ZoomWindow::previous);
	QShortcut *copyImageFile = new QShortcut(QKeySequence::Copy, this);
		connect(copyImageFile, &QShortcut::activated, this, &ZoomWindow::copyImageDataToClipboard);
	QShortcut *toggleFullscreen = new QShortcut(QKeySequence::FullScreen, this);
		connect(toggleFullscreen, &QShortcut::activated, this, &ZoomWindow::toggleFullScreen);

	m_labelTagsLeft = new QAffiche(QVariant(), 0, QColor(), this);
		m_labelTagsLeft->setContextMenuPolicy(Qt::CustomContextMenu);
		m_labelTagsLeft->setTextInteractionFlags(Qt::TextBrowserInteraction);
		connect(m_labelTagsLeft, &QAffiche::customContextMenuRequested, this, &ZoomWindow::contextMenu);
		connect(m_labelTagsLeft, &QAffiche::linkActivated, this, &ZoomWindow::openUrl);
		connect(m_labelTagsLeft, &QAffiche::linkHovered, this, &ZoomWindow::linkHovered);
		connect(m_labelTagsLeft, SIGNAL(middleClicked()), this, SLOT(openInNewTab()));
		ui->scrollAreaWidgetContents->layout()->addWidget(m_labelTagsLeft);

	m_labelTagsTop = new QAffiche(QVariant(), 0, QColor(), this);
		m_labelTagsTop->setWordWrap(true);
		m_labelTagsTop->setContextMenuPolicy(Qt::CustomContextMenu);
		m_labelTagsTop->setTextInteractionFlags(Qt::TextBrowserInteraction);
		connect(m_labelTagsTop, &QAffiche::customContextMenuRequested, this, &ZoomWindow::contextMenu);
		connect(m_labelTagsTop, &QAffiche::linkActivated, this, &ZoomWindow::openUrl);
		connect(m_labelTagsTop, &QAffiche::linkHovered, this, &ZoomWindow::linkHovered);
		connect(m_labelTagsTop, SIGNAL(middleClicked()), this, SLOT(openInNewTab()));
		ui->verticalLayout->insertWidget(0, m_labelTagsTop, 0);

	// Automatically re-color if some settings change
	connect(m_profile, &Profile::favoritesChanged, this, &ZoomWindow::colore);
	connect(m_profile, &Profile::keptForLaterChanged, this, &ZoomWindow::colore);
	connect(m_profile, &Profile::ignoredChanged, this, &ZoomWindow::colore);
	connect(m_profile, &Profile::blacklistChanged, this, &ZoomWindow::colore);

	m_stackedWidget = new QStackedWidget(this);
		ui->verticalLayout->insertWidget(1, m_stackedWidget, 1);
	m_labelImage = new QAffiche(QVariant(), 0, QColor(), this);
		m_labelImage->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
		connect(m_labelImage, SIGNAL(doubleClicked()), this, SLOT(openFile()));
		m_stackedWidget->addWidget(m_labelImage);

	connect(ui->buttonDetails, &QPushButton::clicked, this, &ZoomWindow::showDetails);
	connect(ui->buttonPlus, &QPushButton::toggled, this, &ZoomWindow::updateButtonPlus);

	m_labelImage->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(m_labelImage, &QAffiche::customContextMenuRequested, this, &ZoomWindow::imageContextMenu);

	m_slideshow.setSingleShot(true);
	connect(&m_slideshow, &QTimer::timeout, this, &ZoomWindow::next);

	// Overlay progressbar and image
	ui->overlayLayout->removeWidget(ui->progressBarDownload);
	ui->overlayLayout->addWidget(ui->progressBarDownload, 0, 0, Qt::AlignBottom);
	ui->progressBarDownload->raise();

	// Threads
	m_imageLoaderThread.setObjectName("Image loader thread");
	m_imageLoader = new ImageLoader();
	m_imageLoader->moveToThread(&m_imageLoaderThread);
	m_imageLoaderQueueThread.setObjectName("Image loader queue thread");
	m_imageLoaderQueue = new ImageLoaderQueue(m_imageLoader);
	m_imageLoaderQueue->moveToThread(&m_imageLoaderQueueThread);
	connect(&m_imageLoaderThread, &QThread::finished, m_imageLoader, &QObject::deleteLater);
	connect(&m_imageLoaderQueueThread, &QThread::finished, m_imageLoaderQueue, &QObject::deleteLater);
	connect(this, &ZoomWindow::loadImage, m_imageLoaderQueue, &ImageLoaderQueue::load);
	connect(this, &ZoomWindow::clearLoadQueue, m_imageLoaderQueue, &ImageLoaderQueue::clear);
	connect(m_imageLoaderQueue, &ImageLoaderQueue::finished, this, &ZoomWindow::display);
	m_imageLoaderQueueThread.start();
	m_imageLoaderThread.start();

	// Background color
	QString bg = m_settings->value("imageBackgroundColor", "").toString();
	if (!bg.isEmpty())
	{
		setStyleSheet("#zoomWindow, #scrollAreaWidgetContents { background-color:" + bg + "; }");
		m_labelImage->setStyleSheet("background-color:" + bg);
		m_labelTagsLeft->setStyleSheet("background-color:" + bg);
		m_labelTagsTop->setStyleSheet("background-color:" + bg);
	}

	load(image);
}
void ZoomWindow::go()
{
	ui->labelPools->hide();
	bool whitelisted = false;
	if (!m_settings->value("whitelistedtags").toString().isEmpty())
	{
		QStringList whitelist = m_settings->value("whitelistedtags").toString().split(" ", QString::SkipEmptyParts);
		for (const Tag &t : m_image->tags())
		{
			if (whitelist.contains(t.text()))
			{
				whitelisted = true;
				break;
			}
		}
	}
	if (m_settings->value("autodownload", false).toBool() || (whitelisted && m_settings->value("whitelist_download", "image").toString() == "image"))
	{ saveImage(); }

	m_url = m_image->getDisplayableUrl();

	auto *timer = new QTimer(this);
		connect(timer, SIGNAL(timeout()), this, SLOT(update()));
		timer->setSingleShot(true);
		m_resizeTimer = timer;

	QString pos = m_settings->value("tagsposition", "top").toString();
	if (pos == QLatin1String("auto"))
	{
		if (!m_image->size().isEmpty())
		{
			if (static_cast<double>(m_image->width()) / static_cast<double>(m_image->height()) >= 4.0 / 3.0)
			{ pos = QStringLiteral("top"); }
			else
			{ pos = QStringLiteral("left"); }
		}
		else
		{ pos = QStringLiteral("top"); }
	}

	if (pos == QLatin1String("top"))
	{
		ui->widgetLeft->hide();
		m_labelTagsTop->show();
	}
	else
	{
		m_labelTagsTop->hide();
		m_labelTagsLeft->show();
		ui->widgetLeft->show();
	}

	m_detailsWindow = new DetailsWindow(m_profile, this);
	colore();

	// Load image details (exact tags & co)
	connect(m_image.data(), &Image::finishedLoadingTags, this, &ZoomWindow::replyFinishedDetails, Qt::UniqueConnection);
	m_image->loadDetails();

	if (!m_isFullscreen)
		activateWindow();
}

/**
 * Destructor of the zoomWindow class
 */
ZoomWindow::~ZoomWindow()
{
	if (m_displayMovie != nullptr)
		m_displayMovie->deleteLater();

	m_labelTagsTop->deleteLater();
	m_labelTagsLeft->deleteLater();
	m_detailsWindow->deleteLater();

	// Quit threads
	m_imageLoaderQueueThread.quit();
	m_imageLoaderThread.wait(1000);
	m_imageLoaderThread.quit();
	m_imageLoaderThread.wait(1000);

	delete ui;
}

void ZoomWindow::imageContextMenu()
{
	QMenu *menu = new ImageContextMenu(m_settings, m_image, m_parent, this);

	// Reload action
	QAction *reloadImageAction = new QAction(QIcon(":/images/icons/update.png"), tr("Reload"), menu);
	connect(reloadImageAction, &QAction::triggered, this, &ZoomWindow::reloadImage);

	// Copy actions
	QAction *copyImageAction = new QAction(QIcon(":/images/icons/copy.png"), tr("Copy file"), menu);
	connect(copyImageAction, &QAction::triggered, this, &ZoomWindow::copyImageFileToClipboard);
	QAction *copyDataAction = new QAction(QIcon(":/images/icons/document-binary.png"), tr("Copy data"), menu);
	connect(copyDataAction, &QAction::triggered, this, &ZoomWindow::copyImageDataToClipboard);

	// Insert actions at the beginning
	QAction *first = menu->actions().first();
	menu->insertAction(first, reloadImageAction);
	menu->insertSeparator(first);
	menu->insertAction(first, copyImageAction);
	menu->insertAction(first, copyDataAction);
	menu->insertSeparator(first);

	menu->exec(QCursor::pos());
}
void ZoomWindow::reloadImage()
{
	load(true);
}
void ZoomWindow::copyImageFileToClipboard()
{
	auto *mimeData = new QMimeData();
	mimeData->setUrls({ QUrl::fromLocalFile(m_imagePath) });
	QApplication::clipboard()->setMimeData(mimeData);
}
void ZoomWindow::copyImageDataToClipboard()
{
	QApplication::clipboard()->setPixmap(m_displayImage);
}

void ZoomWindow::showDetails()
{
	m_detailsWindow->setImage(m_image);
	m_detailsWindow->show();
}

void ZoomWindow::openUrl(const QString &url)
{ emit linkClicked(url); }
void ZoomWindow::openPool(const QString &url)
{
	if (url.startsWith(QLatin1String("pool:")))
	{ emit poolClicked(url.rightRef(url.length() - 5).toInt(), m_image->parentSite()->url()); }
	else
	{
		Page *p = new Page(m_profile, m_image->parentSite(), m_profile->getSites().values(), QStringList() << "id:" + url, 1, 1, QStringList(), false, this);
		connect(p, &Page::finishedLoading, this, &ZoomWindow::openPoolId);
		p->load();
	}
}
void ZoomWindow::openPoolId(Page *p)
{
	if (p->images().empty())
	{
		p->deleteLater();
		return;
	}

	m_image = p->images().at(0);
	m_timeout = 300;
	m_loadedDetails = false;
	m_loadedImage = false;
	m_finished = false;
	m_size = 0;
	m_labelImage->hide();
	ui->verticalLayout->removeWidget(m_labelImage);

	go();
}

void ZoomWindow::openSaveDir(bool fav)
{
	// If the file was already saved, we focus on it
	if (!m_imagePath.isEmpty())
	{
		showInGraphicalShell(m_imagePath);<commit_msg>Fix 'destination folder' button showing temp dir in image window (issue #1361)<commit_after>#include "viewer/zoom-window.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QMenu>
#include <QMessageBox>
#include <QScrollBar>
#include <QShortcut>
#include <ui_zoom-window.h>
#include "functions.h"
#include "helpers.h"
#include "image-context-menu.h"
#include "mainwindow.h"
#include "models/filename.h"
#include "models/filtering/post-filter.h"
#include "models/page.h"
#include "models/profile.h"
#include "models/site.h"
#include "settings/optionswindow.h"
#include "tag-context-menu.h"
#include "tags/tag-stylist.h"
#include "threads/image-loader.h"
#include "threads/image-loader-queue.h"
#include "ui/QAffiche.h"
#include "viewer/details-window.h"


ZoomWindow::ZoomWindow(QList<QSharedPointer<Image>> images, const QSharedPointer<Image> &image, Site *site, Profile *profile, mainWindow *parent)
	: QWidget(nullptr, Qt::Window), m_parent(parent), m_profile(profile), m_favorites(profile->getFavorites()), m_viewItLater(profile->getKeptForLater()), m_ignore(profile->getIgnored()), m_settings(profile->getSettings()), ui(new Ui::ZoomWindow), m_site(site), m_timeout(300), m_tooBig(false), m_loadedImage(false), m_loadedDetails(false), m_finished(false), m_size(0), m_fullScreen(nullptr), m_isFullscreen(false), m_isSlideshowRunning(false), m_images(std::move(images)), m_displayImage(QPixmap()), m_displayMovie(nullptr), m_labelImageScaled(false)
{
	setAttribute(Qt::WA_DeleteOnClose);
	ui->setupUi(this);

	m_pendingAction = PendingNothing;
	m_pendingClose = false;

	restoreGeometry(m_settings->value("Zoom/geometry").toByteArray());
	ui->buttonPlus->setChecked(m_settings->value("Zoom/plus", false).toBool());
	ui->progressBarDownload->hide();

	QShortcut *escape = new QShortcut(QKeySequence(Qt::Key_Escape), this);
		connect(escape, &QShortcut::activated, this, &ZoomWindow::close);
	QShortcut *save = new QShortcut(QKeySequence::Save, this);
		connect(save, SIGNAL(activated()), this, SLOT(saveImage()));
	QShortcut *saveAs = new QShortcut(QKeySequence::SaveAs, this);
		connect(saveAs, &QShortcut::activated, this, &ZoomWindow::saveImageAs);
	QShortcut *arrowNext = new QShortcut(QKeySequence(Qt::Key_Right), this);
		connect(arrowNext, &QShortcut::activated, this, &ZoomWindow::next);
	QShortcut *arrowPrevious = new QShortcut(QKeySequence(Qt::Key_Left), this);
		connect(arrowPrevious, &QShortcut::activated, this, &ZoomWindow::previous);
	QShortcut *copyImageFile = new QShortcut(QKeySequence::Copy, this);
		connect(copyImageFile, &QShortcut::activated, this, &ZoomWindow::copyImageDataToClipboard);
	QShortcut *toggleFullscreen = new QShortcut(QKeySequence::FullScreen, this);
		connect(toggleFullscreen, &QShortcut::activated, this, &ZoomWindow::toggleFullScreen);

	m_labelTagsLeft = new QAffiche(QVariant(), 0, QColor(), this);
		m_labelTagsLeft->setContextMenuPolicy(Qt::CustomContextMenu);
		m_labelTagsLeft->setTextInteractionFlags(Qt::TextBrowserInteraction);
		connect(m_labelTagsLeft, &QAffiche::customContextMenuRequested, this, &ZoomWindow::contextMenu);
		connect(m_labelTagsLeft, &QAffiche::linkActivated, this, &ZoomWindow::openUrl);
		connect(m_labelTagsLeft, &QAffiche::linkHovered, this, &ZoomWindow::linkHovered);
		connect(m_labelTagsLeft, SIGNAL(middleClicked()), this, SLOT(openInNewTab()));
		ui->scrollAreaWidgetContents->layout()->addWidget(m_labelTagsLeft);

	m_labelTagsTop = new QAffiche(QVariant(), 0, QColor(), this);
		m_labelTagsTop->setWordWrap(true);
		m_labelTagsTop->setContextMenuPolicy(Qt::CustomContextMenu);
		m_labelTagsTop->setTextInteractionFlags(Qt::TextBrowserInteraction);
		connect(m_labelTagsTop, &QAffiche::customContextMenuRequested, this, &ZoomWindow::contextMenu);
		connect(m_labelTagsTop, &QAffiche::linkActivated, this, &ZoomWindow::openUrl);
		connect(m_labelTagsTop, &QAffiche::linkHovered, this, &ZoomWindow::linkHovered);
		connect(m_labelTagsTop, SIGNAL(middleClicked()), this, SLOT(openInNewTab()));
		ui->verticalLayout->insertWidget(0, m_labelTagsTop, 0);

	// Automatically re-color if some settings change
	connect(m_profile, &Profile::favoritesChanged, this, &ZoomWindow::colore);
	connect(m_profile, &Profile::keptForLaterChanged, this, &ZoomWindow::colore);
	connect(m_profile, &Profile::ignoredChanged, this, &ZoomWindow::colore);
	connect(m_profile, &Profile::blacklistChanged, this, &ZoomWindow::colore);

	m_stackedWidget = new QStackedWidget(this);
		ui->verticalLayout->insertWidget(1, m_stackedWidget, 1);
	m_labelImage = new QAffiche(QVariant(), 0, QColor(), this);
		m_labelImage->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
		connect(m_labelImage, SIGNAL(doubleClicked()), this, SLOT(openFile()));
		m_stackedWidget->addWidget(m_labelImage);

	connect(ui->buttonDetails, &QPushButton::clicked, this, &ZoomWindow::showDetails);
	connect(ui->buttonPlus, &QPushButton::toggled, this, &ZoomWindow::updateButtonPlus);

	m_labelImage->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(m_labelImage, &QAffiche::customContextMenuRequested, this, &ZoomWindow::imageContextMenu);

	m_slideshow.setSingleShot(true);
	connect(&m_slideshow, &QTimer::timeout, this, &ZoomWindow::next);

	// Overlay progressbar and image
	ui->overlayLayout->removeWidget(ui->progressBarDownload);
	ui->overlayLayout->addWidget(ui->progressBarDownload, 0, 0, Qt::AlignBottom);
	ui->progressBarDownload->raise();

	// Threads
	m_imageLoaderThread.setObjectName("Image loader thread");
	m_imageLoader = new ImageLoader();
	m_imageLoader->moveToThread(&m_imageLoaderThread);
	m_imageLoaderQueueThread.setObjectName("Image loader queue thread");
	m_imageLoaderQueue = new ImageLoaderQueue(m_imageLoader);
	m_imageLoaderQueue->moveToThread(&m_imageLoaderQueueThread);
	connect(&m_imageLoaderThread, &QThread::finished, m_imageLoader, &QObject::deleteLater);
	connect(&m_imageLoaderQueueThread, &QThread::finished, m_imageLoaderQueue, &QObject::deleteLater);
	connect(this, &ZoomWindow::loadImage, m_imageLoaderQueue, &ImageLoaderQueue::load);
	connect(this, &ZoomWindow::clearLoadQueue, m_imageLoaderQueue, &ImageLoaderQueue::clear);
	connect(m_imageLoaderQueue, &ImageLoaderQueue::finished, this, &ZoomWindow::display);
	m_imageLoaderQueueThread.start();
	m_imageLoaderThread.start();

	// Background color
	QString bg = m_settings->value("imageBackgroundColor", "").toString();
	if (!bg.isEmpty())
	{
		setStyleSheet("#zoomWindow, #scrollAreaWidgetContents { background-color:" + bg + "; }");
		m_labelImage->setStyleSheet("background-color:" + bg);
		m_labelTagsLeft->setStyleSheet("background-color:" + bg);
		m_labelTagsTop->setStyleSheet("background-color:" + bg);
	}

	load(image);
}
void ZoomWindow::go()
{
	ui->labelPools->hide();
	bool whitelisted = false;
	if (!m_settings->value("whitelistedtags").toString().isEmpty())
	{
		QStringList whitelist = m_settings->value("whitelistedtags").toString().split(" ", QString::SkipEmptyParts);
		for (const Tag &t : m_image->tags())
		{
			if (whitelist.contains(t.text()))
			{
				whitelisted = true;
				break;
			}
		}
	}
	if (m_settings->value("autodownload", false).toBool() || (whitelisted && m_settings->value("whitelist_download", "image").toString() == "image"))
	{ saveImage(); }

	m_url = m_image->getDisplayableUrl();

	auto *timer = new QTimer(this);
		connect(timer, SIGNAL(timeout()), this, SLOT(update()));
		timer->setSingleShot(true);
		m_resizeTimer = timer;

	QString pos = m_settings->value("tagsposition", "top").toString();
	if (pos == QLatin1String("auto"))
	{
		if (!m_image->size().isEmpty())
		{
			if (static_cast<double>(m_image->width()) / static_cast<double>(m_image->height()) >= 4.0 / 3.0)
			{ pos = QStringLiteral("top"); }
			else
			{ pos = QStringLiteral("left"); }
		}
		else
		{ pos = QStringLiteral("top"); }
	}

	if (pos == QLatin1String("top"))
	{
		ui->widgetLeft->hide();
		m_labelTagsTop->show();
	}
	else
	{
		m_labelTagsTop->hide();
		m_labelTagsLeft->show();
		ui->widgetLeft->show();
	}

	m_detailsWindow = new DetailsWindow(m_profile, this);
	colore();

	// Load image details (exact tags & co)
	connect(m_image.data(), &Image::finishedLoadingTags, this, &ZoomWindow::replyFinishedDetails, Qt::UniqueConnection);
	m_image->loadDetails();

	if (!m_isFullscreen)
		activateWindow();
}

/**
 * Destructor of the zoomWindow class
 */
ZoomWindow::~ZoomWindow()
{
	if (m_displayMovie != nullptr)
		m_displayMovie->deleteLater();

	m_labelTagsTop->deleteLater();
	m_labelTagsLeft->deleteLater();
	m_detailsWindow->deleteLater();

	// Quit threads
	m_imageLoaderQueueThread.quit();
	m_imageLoaderThread.wait(1000);
	m_imageLoaderThread.quit();
	m_imageLoaderThread.wait(1000);

	delete ui;
}

void ZoomWindow::imageContextMenu()
{
	QMenu *menu = new ImageContextMenu(m_settings, m_image, m_parent, this);

	// Reload action
	QAction *reloadImageAction = new QAction(QIcon(":/images/icons/update.png"), tr("Reload"), menu);
	connect(reloadImageAction, &QAction::triggered, this, &ZoomWindow::reloadImage);

	// Copy actions
	QAction *copyImageAction = new QAction(QIcon(":/images/icons/copy.png"), tr("Copy file"), menu);
	connect(copyImageAction, &QAction::triggered, this, &ZoomWindow::copyImageFileToClipboard);
	QAction *copyDataAction = new QAction(QIcon(":/images/icons/document-binary.png"), tr("Copy data"), menu);
	connect(copyDataAction, &QAction::triggered, this, &ZoomWindow::copyImageDataToClipboard);

	// Insert actions at the beginning
	QAction *first = menu->actions().first();
	menu->insertAction(first, reloadImageAction);
	menu->insertSeparator(first);
	menu->insertAction(first, copyImageAction);
	menu->insertAction(first, copyDataAction);
	menu->insertSeparator(first);

	menu->exec(QCursor::pos());
}
void ZoomWindow::reloadImage()
{
	load(true);
}
void ZoomWindow::copyImageFileToClipboard()
{
	auto *mimeData = new QMimeData();
	mimeData->setUrls({ QUrl::fromLocalFile(m_imagePath) });
	QApplication::clipboard()->setMimeData(mimeData);
}
void ZoomWindow::copyImageDataToClipboard()
{
	QApplication::clipboard()->setPixmap(m_displayImage);
}

void ZoomWindow::showDetails()
{
	m_detailsWindow->setImage(m_image);
	m_detailsWindow->show();
}

void ZoomWindow::openUrl(const QString &url)
{ emit linkClicked(url); }
void ZoomWindow::openPool(const QString &url)
{
	if (url.startsWith(QLatin1String("pool:")))
	{ emit poolClicked(url.rightRef(url.length() - 5).toInt(), m_image->parentSite()->url()); }
	else
	{
		Page *p = new Page(m_profile, m_image->parentSite(), m_profile->getSites().values(), QStringList() << "id:" + url, 1, 1, QStringList(), false, this);
		connect(p, &Page::finishedLoading, this, &ZoomWindow::openPoolId);
		p->load();
	}
}
void ZoomWindow::openPoolId(Page *p)
{
	if (p->images().empty())
	{
		p->deleteLater();
		return;
	}

	m_image = p->images().at(0);
	m_timeout = 300;
	m_loadedDetails = false;
	m_loadedImage = false;
	m_finished = false;
	m_size = 0;
	m_labelImage->hide();
	ui->verticalLayout->removeWidget(m_labelImage);

	go();
}

void ZoomWindow::openSaveDir(bool fav)
{
	// If the file was already saved, we focus on it
	if (!m_source.isEmpty())
	{
		showInGraphicalShell(m_source);
{'fraction_non_alphanumeric': 0.15941247810268158, 'fraction_numerical': 0.003413735794816512, 'mean_word_length': 7.779179810725552, 'pattern_counts': {'":': 6, '<': 33, '<?xml version=': 0, '>': 211, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2243859', 'n_tokens_mistral': 7752, 'n_tokens_neox': 7426, 'n_words': 1224}