From 5286322063ad120ce93b59c4f55456bd3e0c47d2 Mon Sep 17 00:00:00 2001 From: Ouyang Chunhui Date: Fri, 5 Jul 2024 17:31:35 +0800 Subject: [PATCH] Initial implementation of the plugin framework Plugin RFC #2529 Signed-off-by: Ouyang Chunhui --- ...plementation-of-the-plugin-framework.patch | 1195 +++++++++++++++++ CMakeLists.txt | 6 + data/graphics.qrc | 4 + data/img/material/black/content-print.svg | 41 + data/img/material/black/save-to-pdf.svg | 24 + data/img/material/white/content-print.svg | 56 + data/img/material/white/save-to-pdf.svg | 36 + src/CMakeLists.txt | 9 +- src/core/CMakeLists.txt | 3 + src/core/capturerequest.h | 2 + src/core/corepluginInterface.h | 20 + src/core/flameshot.cpp | 109 +- src/core/pluginmanager.cpp | 157 +++ src/core/pluginmanager.h | 50 + src/main.cpp | 6 + src/tools/CMakeLists.txt | 2 + src/tools/capturetool.h | 16 +- src/tools/print/printtool.cpp | 48 + src/tools/print/printtool.h | 26 + src/tools/save-to-pdf/save-to-pdf.cpp | 48 + src/tools/save-to-pdf/save-to-pdf.h | 26 + src/tools/toolfactory.cpp | 4 + src/utils/confighandler.cpp | 2 + src/utils/screenshotsaver.cpp | 64 + src/utils/screenshotsaver.h | 2 + src/widgets/capture/capturetoolbutton.cpp | 18 +- src/widgets/capture/capturewidget.cpp | 1 + 27 files changed, 1952 insertions(+), 23 deletions(-) create mode 100644 0001-Initial-implementation-of-the-plugin-framework.patch create mode 100644 data/img/material/black/content-print.svg create mode 100644 data/img/material/black/save-to-pdf.svg create mode 100644 data/img/material/white/content-print.svg create mode 100644 data/img/material/white/save-to-pdf.svg create mode 100644 src/core/corepluginInterface.h create mode 100644 src/core/pluginmanager.cpp create mode 100644 src/core/pluginmanager.h create mode 100644 src/tools/print/printtool.cpp create mode 100644 src/tools/print/printtool.h create mode 100644 src/tools/save-to-pdf/save-to-pdf.cpp create mode 100644 src/tools/save-to-pdf/save-to-pdf.h diff --git a/0001-Initial-implementation-of-the-plugin-framework.patch b/0001-Initial-implementation-of-the-plugin-framework.patch new file mode 100644 index 0000000000..18923705e8 --- /dev/null +++ b/0001-Initial-implementation-of-the-plugin-framework.patch @@ -0,0 +1,1195 @@ +From 2ffee62eb2d283825d554f1a6b94b6d36bdfd57a Mon Sep 17 00:00:00 2001 +From: Ouyang Chunhui +Date: Fri, 5 Jul 2024 17:22:46 +0800 +Subject: [PATCH] Initial implementation of the plugin framework + +Plugin RFC #2529 + +Signed-off-by: Ouyang Chunhui +--- + CMakeLists.txt | 6 + + data/graphics.qrc | 4 + + data/img/material/black/content-print.svg | 41 ++++++ + data/img/material/black/save-to-pdf.svg | 24 ++++ + data/img/material/white/content-print.svg | 56 ++++++++ + data/img/material/white/save-to-pdf.svg | 36 +++++ + src/CMakeLists.txt | 9 +- + src/core/CMakeLists.txt | 3 + + src/core/capturerequest.h | 2 + + src/core/corepluginInterface.h | 20 +++ + src/core/flameshot.cpp | 109 ++++++++++++++- + src/core/pluginmanager.cpp | 157 ++++++++++++++++++++++ + src/core/pluginmanager.h | 50 +++++++ + src/main.cpp | 6 + + src/tools/CMakeLists.txt | 2 + + src/tools/capturetool.h | 16 ++- + src/tools/print/printtool.cpp | 48 +++++++ + src/tools/print/printtool.h | 26 ++++ + src/tools/save-to-pdf/save-to-pdf.cpp | 48 +++++++ + src/tools/save-to-pdf/save-to-pdf.h | 26 ++++ + src/tools/toolfactory.cpp | 4 + + src/utils/confighandler.cpp | 2 + + src/utils/screenshotsaver.cpp | 64 +++++++++ + src/utils/screenshotsaver.h | 2 + + src/widgets/capture/capturetoolbutton.cpp | 18 +-- + src/widgets/capture/capturewidget.cpp | 1 + + 26 files changed, 757 insertions(+), 23 deletions(-) + create mode 100644 data/img/material/black/content-print.svg + create mode 100644 data/img/material/black/save-to-pdf.svg + create mode 100644 data/img/material/white/content-print.svg + create mode 100644 data/img/material/white/save-to-pdf.svg + create mode 100644 src/core/corepluginInterface.h + create mode 100644 src/core/pluginmanager.cpp + create mode 100644 src/core/pluginmanager.h + create mode 100644 src/tools/print/printtool.cpp + create mode 100644 src/tools/print/printtool.h + create mode 100644 src/tools/save-to-pdf/save-to-pdf.cpp + create mode 100644 src/tools/save-to-pdf/save-to-pdf.h + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1cadbbd2..a49d96a7 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -69,6 +69,12 @@ option(USE_EXTERNAL_SINGLEAPPLICATION "Use external QtSingleApplication library" + option(USE_LAUNCHER_ABSOLUTE_PATH "Use absolute path for the desktop launcher" ON) + option(USE_WAYLAND_CLIPBOARD "USE KF Gui Wayland Clipboard" OFF) + option(DISABLE_UPDATE_CHECKER "Disable check for updates" OFF) ++option(USE_PLUGIN_MANAGER "Activate the Plugin Manager" ON) ++option(USE_WAYLAND_GRIM "Activate the Wayland GRIM screenshot adapter" OFF) ++ ++if (USE_PLUGIN_MANAGER) ++ set(PLUGIN_DIRECTORY "app_plugins" CACHE PATH "Setting the Plugin Manager Plugin Directory") ++endif() + if (DISABLE_UPDATE_CHECKER) + add_compile_definitions(DISABLE_UPDATE_CHECKER) + endif () +diff --git a/data/graphics.qrc b/data/graphics.qrc +index fd1d93d1..bed91511 100644 +--- a/data/graphics.qrc ++++ b/data/graphics.qrc +@@ -99,5 +99,9 @@ + img/material/black/image.svg + img/material/white/apps.svg + img/material/white/image.svg ++ img/material/black/content-print.svg ++ img/material/black/save-to-pdf.svg ++ img/material/white/content-print.svg ++ img/material/white/save-to-pdf.svg + + +diff --git a/data/img/material/black/content-print.svg b/data/img/material/black/content-print.svg +new file mode 100644 +index 00000000..1409b5c0 +--- /dev/null ++++ b/data/img/material/black/content-print.svg +@@ -0,0 +1,41 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/data/img/material/black/save-to-pdf.svg b/data/img/material/black/save-to-pdf.svg +new file mode 100644 +index 00000000..98394b00 +--- /dev/null ++++ b/data/img/material/black/save-to-pdf.svg +@@ -0,0 +1,24 @@ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/data/img/material/white/content-print.svg b/data/img/material/white/content-print.svg +new file mode 100644 +index 00000000..29a0cda4 +--- /dev/null ++++ b/data/img/material/white/content-print.svg +@@ -0,0 +1,56 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/data/img/material/white/save-to-pdf.svg b/data/img/material/white/save-to-pdf.svg +new file mode 100644 +index 00000000..45434f48 +--- /dev/null ++++ b/data/img/material/white/save-to-pdf.svg +@@ -0,0 +1,36 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index c29349a5..74bc2b45 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -8,12 +8,18 @@ find_package( + Network + Svg + DBus +- LinguistTools) ++ LinguistTools ++ PrintSupport) + + if (USE_WAYLAND_CLIPBOARD) + find_package(KF5GuiAddons) + endif() + ++if (USE_PLUGIN_MANAGER) ++ find_package(yaml-cpp) ++endif() ++ ++set(USE_PLUGIN_MANAGER ON) + set(CMAKE_AUTOMOC ON) + set(CMAKE_AUTORCC ON) + set(CMAKE_AUTOUIC ON) +@@ -213,6 +219,7 @@ target_link_libraries( + Qt5::DBus + Qt5::Network + Qt5::Widgets ++ Qt5::PrintSupport + ${QTSINGLEAPPLICATION_LIBRARY} + QtColorWidgets + +diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt +index c933bdd6..5bb3cd53 100644 +--- a/src/core/CMakeLists.txt ++++ b/src/core/CMakeLists.txt +@@ -3,6 +3,8 @@ target_sources(flameshot PRIVATE + flameshotdaemon.h + flameshotdbusadapter.h + qguiappcurrentscreen.h ++ pluginmanager.h ++ corepluginInterface.h + ) + + target_sources(flameshot PRIVATE +@@ -11,6 +13,7 @@ target_sources(flameshot PRIVATE + flameshotdaemon.cpp + flameshotdbusadapter.cpp + qguiappcurrentscreen.cpp ++ pluginmanager.cpp + ) + + IF (WIN32) +diff --git a/src/core/capturerequest.h b/src/core/capturerequest.h +index ac8f885c..ed90cc6a 100644 +--- a/src/core/capturerequest.h ++++ b/src/core/capturerequest.h +@@ -27,6 +27,8 @@ public: + PIN = 16, + UPLOAD = 32, + ACCEPT_ON_SELECT = 64, ++ PRINT_SYSTEM = 128, ++ SAVE_TO_PDF = 256 + }; + + CaptureRequest(CaptureMode mode, +diff --git a/src/core/corepluginInterface.h b/src/core/corepluginInterface.h +new file mode 100644 +index 00000000..54f48672 +--- /dev/null ++++ b/src/core/corepluginInterface.h +@@ -0,0 +1,20 @@ ++#ifndef COREPLUGININTERFACE_H ++#define COREPLUGININTERFACE_H ++ ++#include ++ ++class CorePluginInterface { ++public: ++ virtual ~CorePluginInterface() = 0; ++ virtual bool load(std::map &PluginConfig) = 0; ++ virtual void unload() = 0; ++ virtual bool ImagePost(QPixmap &pixmap) = 0; ++ virtual bool ImageToPDFPost(QPixmap &pixmap) = 0; ++ virtual bool PrintPre(QPixmap &pixmap) = 0; ++}; ++ ++#define FlameshotPlugin_iid "FlameshotPlugin.CorePluginInterface" ++ ++Q_DECLARE_INTERFACE(CorePluginInterface, FlameshotPlugin_iid) ++ ++#endif // COREPLUGININTERFACE_H +diff --git a/src/core/flameshot.cpp b/src/core/flameshot.cpp +index c7eadcad..af564b17 100644 +--- a/src/core/flameshot.cpp ++++ b/src/core/flameshot.cpp +@@ -31,7 +31,15 @@ + #include + #include + #include ++#include + #include ++#include ++#include ++#include ++ ++#ifdef USE_PLUGIN_MANAGER ++#include "core/pluginmanager.h" ++#endif + + #if defined(Q_OS_MACOS) + #include +@@ -352,7 +360,12 @@ void Flameshot::exportCapture(const QPixmap& capture, + int tasks = req.tasks(), mode = req.captureMode(); + QString path = req.path(); + ++ QPixmap PixmapOutputBuffer(capture); ++ + if (tasks & CR::PRINT_GEOMETRY) { ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); ++#endif + QByteArray byteArray; + QBuffer buffer(&byteArray); + QTextStream(stdout) +@@ -361,9 +374,12 @@ void Flameshot::exportCapture(const QPixmap& capture, + } + + if (tasks & CR::PRINT_RAW) { ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); ++#endif + QByteArray byteArray; + QBuffer buffer(&byteArray); +- capture.save(&buffer, "PNG"); ++ PixmapOutputBuffer.save(&buffer, "PNG"); + QFile file; + file.open(stdout, QIODevice::WriteOnly); + +@@ -372,19 +388,35 @@ void Flameshot::exportCapture(const QPixmap& capture, + } + + if (tasks & CR::SAVE) { ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); ++#endif + if (req.path().isEmpty()) { +- saveToFilesystemGUI(capture); ++ saveToFilesystemGUI(PixmapOutputBuffer); + } else { +- saveToFilesystem(capture, path); ++ saveToFilesystem(PixmapOutputBuffer, path); + } + } + ++ if (tasks & CR::SAVE_TO_PDF) { ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->CallImageToPDFPost(PixmapOutputBuffer); ++#endif ++ saveToPDF(PixmapOutputBuffer); ++ } ++ + if (tasks & CR::COPY) { +- FlameshotDaemon::copyToClipboard(capture); ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); ++#endif ++ FlameshotDaemon::copyToClipboard(PixmapOutputBuffer); + } + + if (tasks & CR::PIN) { +- FlameshotDaemon::createPin(capture, selection); ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); ++#endif ++ FlameshotDaemon::createPin(PixmapOutputBuffer, selection); + if (mode == CR::SCREEN_MODE || mode == CR::FULLSCREEN_MODE) { + AbstractLogger::info() + << QObject::tr("Full screen screenshot pinned to screen"); +@@ -392,6 +424,9 @@ void Flameshot::exportCapture(const QPixmap& capture, + } + + if (tasks & CR::UPLOAD) { ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); ++#endif + if (!ConfigHandler().uploadWithoutConfirmation()) { + auto* dialog = new ImgUploadDialog(); + if (dialog->exec() == QDialog::Rejected) { +@@ -399,7 +434,7 @@ void Flameshot::exportCapture(const QPixmap& capture, + } + } + +- ImgUploaderBase* widget = ImgUploaderManager().uploader(capture); ++ ImgUploaderBase* widget = ImgUploaderManager().uploader(PixmapOutputBuffer); + widget->show(); + widget->activateWindow(); + // NOTE: lambda can't capture 'this' because it might be destroyed later +@@ -416,8 +451,68 @@ void Flameshot::exportCapture(const QPixmap& capture, + }); + } + ++ if(tasks & CR::PRINT_SYSTEM) { ++ QPixmap pixmap = capture; ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->CallPrintPre(pixmap); ++#endif ++ QPrinter printer; ++ printer.setPageOrientation(QPageLayout::Orientation::Landscape); ++ ++ QPrintPreviewDialog dialog(&printer); ++ dialog.setWindowFlag(Qt::WindowMinMaxButtonsHint); ++ dialog.setWindowTitle(tr("Print Document")); ++ ++#if defined(Q_OS_WIN) ++ QToolBar *PrintPreviewToolbar = dialog.findChild(); ++ QList List = PrintPreviewToolbar->actions(); ++ int index = 0; ++ QSet RemoveIndex; ++ RemoveIndex.insert(0); ++ RemoveIndex.insert(1); ++ RemoveIndex.insert(16); ++ RemoveIndex.insert(17); ++ RemoveIndex.insert(18); ++ const int PrintAction = 21; ++ QSet RemoveList; ++ foreach(auto it, List) { ++ if(RemoveIndex.find(index) != RemoveIndex.end()) { ++ RemoveList.insert(it); ++ } ++ if(index == PrintAction) { ++ it->setIcon(QIcon(":/img/material/black/content-print.svg")); ++ } ++ index++; ++ } ++ foreach(auto it, List) { ++ if(RemoveList.find(it) != RemoveList.end()) { ++ PrintPreviewToolbar->removeAction(it); ++ } ++ } ++ ++#endif ++ connect(&dialog, &QPrintPreviewDialog::paintRequested, [&](QPrinter *printer) { ++ QPainter painter(printer); ++ if((pixmap.size().width() >= printer->width()) || ++ (pixmap.size().height() >= printer->height())) { ++ pixmap = pixmap.scaled(printer->width(), printer->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); ++ } else if(pixmap.size().width() >= (printer->width()/2)) { ++ pixmap = pixmap.scaledToWidth(printer->width(), Qt::SmoothTransformation); ++ if(pixmap.size().height() >= printer->height()) { ++ pixmap = pixmap.scaledToHeight(printer->height(), Qt::SmoothTransformation); ++ } ++ } ++ ++ QRect rect((printer->width() - pixmap.size().width()) /2, ++ (printer->height() - pixmap.size().height()) /2, ++ pixmap.size().width(), pixmap.size().height()); ++ painter.drawPixmap(rect, pixmap); ++ }); ++ dialog.exec(); ++ } ++ + if (!(tasks & CR::UPLOAD)) { +- emit captureTaken(capture); ++ emit captureTaken(PixmapOutputBuffer); + } + } + +diff --git a/src/core/pluginmanager.cpp b/src/core/pluginmanager.cpp +new file mode 100644 +index 00000000..22aaf2e4 +--- /dev/null ++++ b/src/core/pluginmanager.cpp +@@ -0,0 +1,157 @@ ++#ifdef USE_PLUGIN_MANAGER ++ ++#include "pluginmanager.h" ++#include ++#include ++#include ++#include "corepluginInterface.h" ++ ++PluginManager::PluginManager() { ++ ++} ++ ++PluginManager *PluginManager::getInstance() { ++ static PluginManager pluginManager; ++ qDebug() << QObject::tr("Get the plugin manager interface: ").toStdString().c_str() << &pluginManager; ++ return &pluginManager; ++} ++ ++void PluginManager::LoopDirsPlugins(QString Base, std::function Callback) { ++ QDir dirs(Base); ++ if(dirs.exists()) { ++ dirs.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); ++ QFileInfoList fileList = dirs.entryInfoList(); ++ foreach(QFileInfo fileInfo, fileList) { ++ if (Base != pluginDir && fileInfo.isDir()) { ++ QFileInfo infocheck(fileInfo.absolutePath() + PluginDefineYaml); ++ if(!infocheck.exists()) { ++ LoopDirsPlugins(fileInfo.absoluteFilePath(), Callback); ++ } ++ } else if(Base == pluginDir && fileInfo.isDir()) { ++ LoopDirsPlugins(fileInfo.absoluteFilePath(), Callback); ++ } else if(fileInfo.isFile()) { ++ if(fileInfo.fileName() == PluginDefineYaml) { ++ Callback(fileInfo.absoluteFilePath()); ++ } ++ } ++ } ++ } ++} ++ ++int PluginManager::LoadPlugins() { ++ int count = 0; ++ LoopDirsPlugins(pluginDir, [&](QString PluginInfoDefaultYaml) { ++ qDebug() << QObject::tr("Get Plugin Definde: ").toStdString().c_str() << PluginInfoDefaultYaml; ++ YAML::Node config; ++ try { ++ config = YAML::LoadFile(PluginInfoDefaultYaml.toStdString()); ++ } catch(std::exception &e) { ++ qDebug() << QObject::tr("Get Plugin Error: ").toStdString().c_str() << e.what() << PluginInfoDefaultYaml; ++ return; ++ } ++ ++ PluginInfo Info; ++ Info.PluginInfoFullPath = PluginInfoDefaultYaml; ++ Info.PluginName = QString::fromStdString(config["plugin"]["name"].as()); ++ if (config["plugin"]["type"].as() == "qt") { ++ Info.PluginType = PluginInfo::QTPlugin; ++ } ++ ++ QString plugin = QFileInfo(PluginInfoDefaultYaml).absolutePath() + "/" + QString::fromStdString(config["plugin"]["file"].as()); ++ Info.Pluginfile = plugin; ++ ++ std::map PluginConfig = config["plugin"]["config"].as>(); ++ ++ QPluginLoader *Loader = new QPluginLoader(Info.Pluginfile); ++ if(Loader) { ++ if(Loader->load()) { ++ CorePluginInterface *Interface = qobject_cast(Loader->instance()); ++ if(Interface->load(PluginConfig)) { ++ Info.PluginLoader = Loader; ++ } ++ } ++ ++ this->PluginLists.append(Info); ++ ++ count++; ++ } ++ ++ }); ++ qDebug() << QObject::tr("Get Plugin Count: ").toStdString().c_str() << count; ++ return count; ++} ++ ++bool PluginManager::UnLoadPlugins() { ++ foreach(auto Info, this->PluginLists) { ++ if(Info.PluginType == PluginInfo::QTPlugin) { ++ QPluginLoader *Loader = reinterpret_cast(Info.PluginLoader); ++ if(Loader) { ++ delete Loader; ++ Info.PluginLoader = nullptr; ++ } ++ } ++ } ++ this->PluginLists.clear(); ++ return false; ++} ++ ++bool PluginManager::CallImagePost(QPixmap &pixmap) { ++ bool Result = false; ++ foreach(auto Info, this->PluginLists) { ++ if(Info.PluginType == PluginInfo::QTPlugin) { ++ qDebug() << QObject::tr("Call Plugin(ImagePost): ").toStdString().c_str() << Info.PluginName; ++ qDebug() << QObject::tr("Call Plugin(ImagePost) YAML FileName: ").toStdString().c_str() << Info.PluginInfoFullPath; ++ qDebug() << QObject::tr("Call Plugin(ImagePost) Qt Plugin: ").toStdString().c_str() << Info.Pluginfile; ++ if (Info.PluginType == PluginInfo::QTPlugin) { ++ QPluginLoader *Loader = reinterpret_cast(Info.PluginLoader); ++ if(Loader) { ++ CorePluginInterface *Interface = qobject_cast(Loader->instance()); ++ Interface->ImagePost(pixmap); ++ Result = true; ++ } ++ } ++ } ++ } ++ return Result; ++} ++ ++bool PluginManager::CallImageToPDFPost(QPixmap &pixmap) { ++ bool Result = false; ++ foreach(auto Info, this->PluginLists) { ++ if(Info.PluginType == PluginInfo::QTPlugin) { ++ qDebug() << QObject::tr("Call Plugin(ImageToPDFPost): ").toStdString().c_str() << Info.PluginName; ++ qDebug() << QObject::tr("Call Plugin(ImageToPDFPost) YAML FileName: ").toStdString().c_str() << Info.PluginInfoFullPath; ++ qDebug() << QObject::tr("Call Plugin(ImageToPDFPost) Qt Plugin: ").toStdString().c_str() << Info.Pluginfile; ++ if (Info.PluginType == PluginInfo::QTPlugin) { ++ QPluginLoader *Loader = reinterpret_cast(Info.PluginLoader); ++ if(Loader) { ++ CorePluginInterface *Interface = qobject_cast(Loader->instance()); ++ Interface->ImageToPDFPost(pixmap); ++ Result = true; ++ } ++ } ++ } ++ } ++ return Result; ++} ++ ++bool PluginManager::CallPrintPre(QPixmap &pixmap) { ++ bool Result = false; ++ foreach(auto Info, this->PluginLists) { ++ if(Info.PluginType == PluginInfo::QTPlugin) { ++ qDebug() << QObject::tr("Call Plugin(PrintPre): ").toStdString().c_str() << Info.PluginName; ++ qDebug() << QObject::tr("Call Plugin(PrintPre) YAML FileName: ").toStdString().c_str() << Info.PluginInfoFullPath; ++ qDebug() << QObject::tr("Call Plugin(PrintPre) Qt Plugin: ").toStdString().c_str() << Info.Pluginfile; ++ if (Info.PluginType == PluginInfo::QTPlugin) { ++ QPluginLoader *Loader = reinterpret_cast(Info.PluginLoader); ++ if(Loader) { ++ CorePluginInterface *Interface = qobject_cast(Loader->instance()); ++ Interface->PrintPre(pixmap); ++ Result = true; ++ } ++ } ++ } ++ } ++ return Result; ++} ++#endif //USE_PLUGIN_MANAGER +diff --git a/src/core/pluginmanager.h b/src/core/pluginmanager.h +new file mode 100644 +index 00000000..4b32c21e +--- /dev/null ++++ b/src/core/pluginmanager.h +@@ -0,0 +1,50 @@ ++#ifndef PLUGINMANAGER_H ++#define PLUGINMANAGER_H ++ ++#ifdef USE_PLUGIN_MANAGER ++ ++#define GET_BUILD_SET(x) #x ++#define BUILD_DEFINE_CONV_C_STRING(x) GET_BUILD_SET(x) ++ ++#include ++#include ++#include ++#include ++ ++const QString pluginDir = BUILD_DEFINE_CONV_C_STRING(PLUGIN_DIRECTORY); ++ ++const QString PluginDefineYaml = "plugin.yaml"; ++ ++typedef struct _PluginInfo { ++ QString PluginName; ++ QString PluginInfoFullPath; ++ enum Type { ++ QTPlugin, ++ PyPlugin, /*no used*/ ++ LuaPlugin /*no used*/ ++ }PluginType; ++ QString Pluginfile; ++ void *PluginLoader; ++}PluginInfo; ++ ++class PluginManager ++{ ++ typedef void CallbackPluginLoads(QString PluginInfoDefaultYaml); ++private: ++ PluginManager(); ++public: ++ static PluginManager *getInstance(); ++ int LoadPlugins(); ++ bool UnLoadPlugins(); ++ bool CallImagePost(QPixmap &pixmap); ++ bool CallImageToPDFPost(QPixmap &pixmap); ++ bool CallPrintPre(QPixmap &pixmap); ++private: ++ static void LoopDirsPlugins(QString Base, std::function Callback); ++private: ++ QList PluginLists; ++}; ++ ++#endif //USE_PLUGIN_MANAGER ++ ++#endif // PLUGINMANAGER_H +diff --git a/src/main.cpp b/src/main.cpp +index 23d3157e..b5517313 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -32,6 +32,9 @@ + #include + #include + #endif ++#ifdef USE_PLUGIN_MANAGER ++#include "core/pluginmanager.h" ++#endif + + #ifdef Q_OS_LINUX + // source: https://github.com/ksnip/ksnip/issues/416 +@@ -126,6 +129,9 @@ void reinitializeAsQApplication(int& argc, char* argv[]) + + int main(int argc, char* argv[]) + { ++#ifdef USE_PLUGIN_MANAGER ++ PluginManager::getInstance()->LoadPlugins(); ++#endif + #ifdef Q_OS_LINUX + wayland_hacks(); + #endif +diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt +index d2a62924..6712ca6a 100644 +--- a/src/tools/CMakeLists.txt ++++ b/src/tools/CMakeLists.txt +@@ -3,9 +3,11 @@ target_sources(flameshot PRIVATE pixelate/pixelatetool.h pixelate/pixelatetool.c + target_sources(flameshot PRIVATE circle/circletool.h circle/circletool.cpp) + target_sources(flameshot PRIVATE circlecount/circlecounttool.h circlecount/circlecounttool.cpp) + target_sources(flameshot PRIVATE copy/copytool.h copy/copytool.cpp) ++target_sources(flameshot PRIVATE print/printtool.h print/printtool.cpp) + target_sources(flameshot PRIVATE exit/exittool.h exit/exittool.cpp) + target_sources(flameshot PRIVATE sizeincrease/sizeincreasetool.h sizeincrease/sizeincreasetool.cpp) + target_sources(flameshot PRIVATE sizedecrease/sizedecreasetool.h sizedecrease/sizedecreasetool.cpp) ++target_sources(flameshot PRIVATE save-to-pdf/save-to-pdf.h save-to-pdf/save-to-pdf.cpp) + target_sources( + flameshot + PRIVATE imgupload/storages/imgur/imguruploader.h +diff --git a/src/tools/capturetool.h b/src/tools/capturetool.h +index a095d618..0783e394 100644 +--- a/src/tools/capturetool.h ++++ b/src/tools/capturetool.h +@@ -41,13 +41,15 @@ public: + TYPE_OPEN_APP = 14, + TYPE_PIXELATE = 15, + TYPE_REDO = 16, +- TYPE_PIN = 17, +- TYPE_TEXT = 18, +- TYPE_CIRCLECOUNT = 19, +- TYPE_SIZEINCREASE = 20, +- TYPE_SIZEDECREASE = 21, +- TYPE_INVERT = 22, +- TYPE_ACCEPT = 23, ++ TYPE_PRINT = 17, ++ TYPE_PIN = 18, ++ TYPE_TEXT = 19, ++ TYPE_CIRCLECOUNT = 20, ++ TYPE_SIZEINCREASE = 21, ++ TYPE_SIZEDECREASE = 22, ++ TYPE_INVERT = 23, ++ TYPE_ACCEPT = 24, ++ TYPE_SAVE_TO_PDF = 25 + }; + Q_ENUM(Type); + +diff --git a/src/tools/print/printtool.cpp b/src/tools/print/printtool.cpp +new file mode 100644 +index 00000000..b73cb23a +--- /dev/null ++++ b/src/tools/print/printtool.cpp +@@ -0,0 +1,48 @@ ++// SPDX-License-Identifier: GPL-3.0-or-later ++// SPDX-FileCopyrightText: 2017-2019 Ouyang Chunhui & Contributor ++ ++#include "printtool.h" ++#include "src/utils/screenshotsaver.h" ++#include ++ ++PrintTool::PrintTool(QObject* parent) ++ : AbstractActionTool(parent) ++{} ++ ++bool PrintTool::closeOnButtonPressed() const ++{ ++ return true; ++} ++ ++QIcon PrintTool::icon(const QColor& background, bool inEditor) const ++{ ++ Q_UNUSED(inEditor) ++ return QIcon(iconPath(background) + "content-print.svg"); ++} ++QString PrintTool::name() const ++{ ++ return tr("Print"); ++} ++ ++CaptureTool::Type PrintTool::type() const ++{ ++ return CaptureTool::TYPE_PRINT; ++} ++ ++QString PrintTool::description() const ++{ ++ return tr("Print"); ++} ++ ++CaptureTool* PrintTool::copy(QObject* parent) ++{ ++ return new PrintTool(parent); ++} ++ ++void PrintTool::pressed(CaptureContext& context) ++{ ++ emit requestAction(REQ_CLEAR_SELECTION); ++ context.request.addTask(CaptureRequest::PRINT_SYSTEM); ++ emit requestAction(REQ_CAPTURE_DONE_OK); ++ emit requestAction(REQ_CLOSE_GUI); ++} +diff --git a/src/tools/print/printtool.h b/src/tools/print/printtool.h +new file mode 100644 +index 00000000..42ae384e +--- /dev/null ++++ b/src/tools/print/printtool.h +@@ -0,0 +1,26 @@ ++// SPDX-License-Identifier: GPL-3.0-or-later ++// SPDX-FileCopyrightText: 2017-2019 Ouyang Chunhui & Contributor ++ ++#pragma once ++ ++#include "src/tools/abstractactiontool.h" ++ ++class PrintTool : public AbstractActionTool ++{ ++ Q_OBJECT ++public: ++ explicit PrintTool(QObject* parent = nullptr); ++ bool closeOnButtonPressed() const override; ++ ++ QIcon icon(const QColor& background, bool inEditor) const override; ++ QString name() const override; ++ QString description() const override; ++ ++ CaptureTool* copy(QObject* parent = nullptr) override; ++ ++protected: ++ CaptureTool::Type type() const override; ++ ++public slots: ++ void pressed(CaptureContext& context) override; ++}; +diff --git a/src/tools/save-to-pdf/save-to-pdf.cpp b/src/tools/save-to-pdf/save-to-pdf.cpp +new file mode 100644 +index 00000000..46fbc7e6 +--- /dev/null ++++ b/src/tools/save-to-pdf/save-to-pdf.cpp +@@ -0,0 +1,48 @@ ++// SPDX-License-Identifier: GPL-3.0-or-later ++// SPDX-FileCopyrightText: 2017-2019 Ouyang Chunhui & Contributor ++ ++#include "save-to-pdf.h" ++#include "src/utils/screenshotsaver.h" ++#include ++ ++SaveToPDFTool::SaveToPDFTool(QObject* parent) ++ : AbstractActionTool(parent) ++{} ++ ++bool SaveToPDFTool::closeOnButtonPressed() const ++{ ++ return true; ++} ++ ++QIcon SaveToPDFTool::icon(const QColor& background, bool inEditor) const ++{ ++ Q_UNUSED(inEditor) ++ return QIcon(iconPath(background) + "save-to-pdf.svg"); ++} ++QString SaveToPDFTool::name() const ++{ ++ return tr("Save To PDF"); ++} ++ ++CaptureTool::Type SaveToPDFTool::type() const ++{ ++ return CaptureTool::TYPE_PRINT; ++} ++ ++QString SaveToPDFTool::description() const ++{ ++ return tr("Save To PDF"); ++} ++ ++CaptureTool* SaveToPDFTool::copy(QObject* parent) ++{ ++ return new SaveToPDFTool(parent); ++} ++ ++void SaveToPDFTool::pressed(CaptureContext& context) ++{ ++ emit requestAction(REQ_CLEAR_SELECTION); ++ context.request.addTask(CaptureRequest::SAVE_TO_PDF); ++ emit requestAction(REQ_CAPTURE_DONE_OK); ++ emit requestAction(REQ_CLOSE_GUI); ++} +diff --git a/src/tools/save-to-pdf/save-to-pdf.h b/src/tools/save-to-pdf/save-to-pdf.h +new file mode 100644 +index 00000000..97c35f53 +--- /dev/null ++++ b/src/tools/save-to-pdf/save-to-pdf.h +@@ -0,0 +1,26 @@ ++// SPDX-License-Identifier: GPL-3.0-or-later ++// SPDX-FileCopyrightText: 2017-2019 Ouyang Chunhui & Contributor ++ ++#pragma once ++ ++#include "src/tools/abstractactiontool.h" ++ ++class SaveToPDFTool : public AbstractActionTool ++{ ++ Q_OBJECT ++public: ++ explicit SaveToPDFTool(QObject* parent = nullptr); ++ bool closeOnButtonPressed() const override; ++ ++ QIcon icon(const QColor& background, bool inEditor) const override; ++ QString name() const override; ++ QString description() const override; ++ ++ CaptureTool* copy(QObject* parent = nullptr) override; ++ ++protected: ++ CaptureTool::Type type() const override; ++ ++public slots: ++ void pressed(CaptureContext& context) override; ++}; +diff --git a/src/tools/toolfactory.cpp b/src/tools/toolfactory.cpp +index 98ed0ab3..5910fd82 100644 +--- a/src/tools/toolfactory.cpp ++++ b/src/tools/toolfactory.cpp +@@ -20,9 +20,11 @@ + #include "rectangle/rectangletool.h" + #include "redo/redotool.h" + #include "save/savetool.h" ++#include "save-to-pdf/save-to-pdf.h" + #include "selection/selectiontool.h" + #include "sizedecrease/sizedecreasetool.h" + #include "sizeincrease/sizeincreasetool.h" ++#include "print/printtool.h" + #include "text/texttool.h" + #include "undo/undotool.h" + +@@ -48,6 +50,7 @@ CaptureTool* ToolFactory::CreateTool(CaptureTool::Type t, QObject* parent) + if_TYPE_return_TOOL(TYPE_UNDO, UndoTool); + if_TYPE_return_TOOL(TYPE_COPY, CopyTool); + if_TYPE_return_TOOL(TYPE_SAVE, SaveTool); ++ if_TYPE_return_TOOL(TYPE_SAVE_TO_PDF, SaveToPDFTool); + if_TYPE_return_TOOL(TYPE_EXIT, ExitTool); + if_TYPE_return_TOOL(TYPE_IMAGEUPLOADER, ImgUploaderTool); + #if !defined(Q_OS_MACOS) +@@ -55,6 +58,7 @@ CaptureTool* ToolFactory::CreateTool(CaptureTool::Type t, QObject* parent) + #endif + if_TYPE_return_TOOL(TYPE_PIXELATE, PixelateTool); + if_TYPE_return_TOOL(TYPE_REDO, RedoTool); ++ if_TYPE_return_TOOL(TYPE_PRINT, PrintTool); + if_TYPE_return_TOOL(TYPE_PIN, PinTool); + if_TYPE_return_TOOL(TYPE_TEXT, TextTool); + if_TYPE_return_TOOL(TYPE_CIRCLECOUNT, CircleCountTool); +diff --git a/src/utils/confighandler.cpp b/src/utils/confighandler.cpp +index 485fb265..91a87007 100644 +--- a/src/utils/confighandler.cpp ++++ b/src/utils/confighandler.cpp +@@ -142,6 +142,7 @@ static QMap> recognizedShortcuts = { + SHORTCUT("TYPE_UNDO" , "Ctrl+Z" ), + SHORTCUT("TYPE_COPY" , "Ctrl+C" ), + SHORTCUT("TYPE_SAVE" , "Ctrl+S" ), ++ SHORTCUT("TYPE_SAVE_TO_PDF" , ), + SHORTCUT("TYPE_ACCEPT" , "Return" ), + SHORTCUT("TYPE_EXIT" , "Ctrl+Q" ), + SHORTCUT("TYPE_IMAGEUPLOADER" , ), +@@ -179,6 +180,7 @@ static QMap> recognizedShortcuts = { + SHORTCUT("TYPE_SIZEINCREASE" , ), + SHORTCUT("TYPE_SIZEDECREASE" , ), + SHORTCUT("TYPE_CIRCLECOUNT" , ), ++ SHORTCUT("TYPE_PRINT", ) + }; + // clang-format on + +diff --git a/src/utils/screenshotsaver.cpp b/src/utils/screenshotsaver.cpp +index f7f5a710..59326815 100644 +--- a/src/utils/screenshotsaver.cpp ++++ b/src/utils/screenshotsaver.cpp +@@ -23,6 +23,10 @@ + #include + #include + #include ++#include ++#ifdef USE_PLUGIN_MANAGER ++#include "core/pluginmanager.h" ++#endif + #if defined(Q_OS_MACOS) + #include "src/widgets/capture/capturewidget.h" + #endif +@@ -101,6 +105,23 @@ QString ShowSaveFileDialog(const QString& title, const QString& directory) + } + } + ++QString ShowSaveToPDFDialog(const QString& title, const QString& directory) ++{ ++ QFileDialog dialog(nullptr, title, directory); ++ dialog.setAcceptMode(QFileDialog::AcceptSave); ++ ++ // Build string list of supported image formats ++ QStringList mimeTypeList; ++ mimeTypeList.append("application/pdf"); ++ dialog.setMimeTypeFilters(mimeTypeList); ++ if (dialog.exec() == QDialog::Accepted) { ++ return dialog.selectedFiles().constFirst(); ++ } else { ++ return {}; ++ } ++} ++ ++ + void saveToClipboardMime(const QPixmap& capture, const QString& imageType) + { + QByteArray array; +@@ -168,6 +189,49 @@ void saveToClipboard(const QPixmap& capture) + } + } + ++bool saveToPDF(const QPixmap& capture) { ++ bool okay = false; ++ QString savePath; ++ ConfigHandler config; ++ savePath = QDir::toNativeSeparators( ++ ShowSaveToPDFDialog(QObject::tr("Save screenshot To PDF"), savePath)); ++ if(savePath.endsWith(".pdf", Qt::CaseInsensitive)) { ++ QPrinter printer(QPrinter::HighResolution); ++ printer.setOutputFormat(QPrinter::PdfFormat); ++ printer.setPageOrientation(QPageLayout::Landscape); ++ printer.setPageSize(QPageSize::A4); ++ printer.setOutputFileName(savePath); ++ QPainter painter(&printer); ++ QPixmap new_capture = capture.scaled(printer.width(), printer.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); ++ QRect rect(0, 0, new_capture.size().width(), new_capture.size().height()); ++ painter.drawPixmap(rect, new_capture); ++ okay = true; ++ } ++ ++ if(okay) { ++ QString pathNoFile = ++ savePath.left(savePath.lastIndexOf(QDir::separator())); ++ ++ ConfigHandler().setSavePath(pathNoFile); ++ ++ QString msg = QObject::tr("Capture saved as ") + savePath; ++ AbstractLogger().attachNotificationPath(savePath) << msg; ++ ++ if (config.copyPathAfterSave()) { ++ FlameshotDaemon::copyToClipboard( ++ savePath, QObject::tr("Path copied to clipboard as ") + savePath); ++ } ++ } else { ++ QString msg = QObject::tr("Error trying to save as ") + savePath; ++ QMessageBox saveErrBox( ++ QMessageBox::Warning, QObject::tr("Save Error"), msg); ++ saveErrBox.setWindowIcon(QIcon(GlobalValues::iconPath())); ++ saveErrBox.exec(); ++ } ++ ++ return okay; ++} ++ + bool saveToFilesystemGUI(const QPixmap& capture) + { + bool okay = false; +diff --git a/src/utils/screenshotsaver.h b/src/utils/screenshotsaver.h +index 9face346..a1675ead 100644 +--- a/src/utils/screenshotsaver.h ++++ b/src/utils/screenshotsaver.h +@@ -11,6 +11,8 @@ bool saveToFilesystem(const QPixmap& capture, + const QString& path, + const QString& messagePrefix = ""); + QString ShowSaveFileDialog(const QString& title, const QString& directory); ++QString ShowSaveToPDFDialog(const QString& title, const QString& directory); + void saveToClipboardMime(const QPixmap& capture, const QString& imageType); + void saveToClipboard(const QPixmap& capture); + bool saveToFilesystemGUI(const QPixmap& capture); ++bool saveToPDF(const QPixmap& capture); +diff --git a/src/widgets/capture/capturetoolbutton.cpp b/src/widgets/capture/capturetoolbutton.cpp +index bc51eb72..be211d1d 100644 +--- a/src/widgets/capture/capturetoolbutton.cpp ++++ b/src/widgets/capture/capturetoolbutton.cpp +@@ -146,17 +146,18 @@ static std::map buttonTypeOrder + { CaptureTool::TYPE_SELECTIONINDICATOR, 11 }, + { CaptureTool::TYPE_MOVESELECTION, 12 }, { CaptureTool::TYPE_UNDO, 13 }, + { CaptureTool::TYPE_REDO, 14 }, { CaptureTool::TYPE_COPY, 15 }, +- { CaptureTool::TYPE_SAVE, 16 }, { CaptureTool::TYPE_IMAGEUPLOADER, 17 }, +- { CaptureTool::TYPE_ACCEPT, 18 }, ++ { CaptureTool::TYPE_SAVE, 16 }, { CaptureTool::TYPE_SAVE_TO_PDF, 17}, ++ { CaptureTool::TYPE_PRINT, 18}, { CaptureTool::TYPE_IMAGEUPLOADER, 29 }, ++ { CaptureTool::TYPE_ACCEPT, 20 }, + #if !defined(Q_OS_MACOS) +- { CaptureTool::TYPE_OPEN_APP, 19 }, { CaptureTool::TYPE_EXIT, 20 }, +- { CaptureTool::TYPE_PIN, 21 }, ++ { CaptureTool::TYPE_OPEN_APP, 21 }, { CaptureTool::TYPE_EXIT, 22 }, ++ { CaptureTool::TYPE_PIN, 23 }, + #else +- { CaptureTool::TYPE_EXIT, 19 }, { CaptureTool::TYPE_PIN, 20 }, ++ { CaptureTool::TYPE_EXIT, 21 }, { CaptureTool::TYPE_PIN, 22 }, + #endif + +- { CaptureTool::TYPE_SIZEINCREASE, 22 }, +- { CaptureTool::TYPE_SIZEDECREASE, 23 }, ++ { CaptureTool::TYPE_SIZEINCREASE, 24 }, ++ { CaptureTool::TYPE_SIZEDECREASE, 25 }, + }; + + int CaptureToolButton::getPriorityByButton(CaptureTool::Type b) +@@ -174,7 +175,8 @@ QList CaptureToolButton::iterableButtonTypes = { + CaptureTool::TYPE_CIRCLECOUNT, CaptureTool::TYPE_PIXELATE, + CaptureTool::TYPE_MOVESELECTION, CaptureTool::TYPE_UNDO, + CaptureTool::TYPE_REDO, CaptureTool::TYPE_COPY, +- CaptureTool::TYPE_SAVE, CaptureTool::TYPE_EXIT, ++ CaptureTool::TYPE_SAVE, CaptureTool::TYPE_SAVE_TO_PDF, ++ CaptureTool::TYPE_PRINT, CaptureTool::TYPE_EXIT, + CaptureTool::TYPE_IMAGEUPLOADER, + #if !defined(Q_OS_MACOS) + CaptureTool::TYPE_OPEN_APP, +diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp +index 49ebff97..92456946 100644 +--- a/src/widgets/capture/capturewidget.cpp ++++ b/src/widgets/capture/capturewidget.cpp +@@ -296,6 +296,7 @@ void CaptureWidget::initButtons() + // Remove irrelevant buttons from both lists + for (auto* buttonList : { &allButtonTypes, &visibleButtonTypes }) { + buttonList->removeOne(CaptureTool::TYPE_SAVE); ++ buttonList->removeOne(CaptureTool::TYPE_SAVE_TO_PDF); + buttonList->removeOne(CaptureTool::TYPE_COPY); + buttonList->removeOne(CaptureTool::TYPE_IMAGEUPLOADER); + buttonList->removeOne(CaptureTool::TYPE_OPEN_APP); +-- +2.42.0 + diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cadbbd2cd..a49d96a7f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,12 @@ option(USE_EXTERNAL_SINGLEAPPLICATION "Use external QtSingleApplication library" option(USE_LAUNCHER_ABSOLUTE_PATH "Use absolute path for the desktop launcher" ON) option(USE_WAYLAND_CLIPBOARD "USE KF Gui Wayland Clipboard" OFF) option(DISABLE_UPDATE_CHECKER "Disable check for updates" OFF) +option(USE_PLUGIN_MANAGER "Activate the Plugin Manager" ON) +option(USE_WAYLAND_GRIM "Activate the Wayland GRIM screenshot adapter" OFF) + +if (USE_PLUGIN_MANAGER) + set(PLUGIN_DIRECTORY "app_plugins" CACHE PATH "Setting the Plugin Manager Plugin Directory") +endif() if (DISABLE_UPDATE_CHECKER) add_compile_definitions(DISABLE_UPDATE_CHECKER) endif () diff --git a/data/graphics.qrc b/data/graphics.qrc index fd1d93d139..bed91511de 100644 --- a/data/graphics.qrc +++ b/data/graphics.qrc @@ -99,5 +99,9 @@ img/material/black/image.svg img/material/white/apps.svg img/material/white/image.svg + img/material/black/content-print.svg + img/material/black/save-to-pdf.svg + img/material/white/content-print.svg + img/material/white/save-to-pdf.svg diff --git a/data/img/material/black/content-print.svg b/data/img/material/black/content-print.svg new file mode 100644 index 0000000000..1409b5c0d0 --- /dev/null +++ b/data/img/material/black/content-print.svg @@ -0,0 +1,41 @@ + + + + + + + + + + diff --git a/data/img/material/black/save-to-pdf.svg b/data/img/material/black/save-to-pdf.svg new file mode 100644 index 0000000000..98394b00b0 --- /dev/null +++ b/data/img/material/black/save-to-pdf.svg @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/data/img/material/white/content-print.svg b/data/img/material/white/content-print.svg new file mode 100644 index 0000000000..29a0cda4e1 --- /dev/null +++ b/data/img/material/white/content-print.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + diff --git a/data/img/material/white/save-to-pdf.svg b/data/img/material/white/save-to-pdf.svg new file mode 100644 index 0000000000..45434f480e --- /dev/null +++ b/data/img/material/white/save-to-pdf.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b1abf3791c..9a3078d7ad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,12 +8,18 @@ find_package( Network Svg DBus - LinguistTools) + LinguistTools + PrintSupport) if (USE_WAYLAND_CLIPBOARD) find_package(KF5GuiAddons) endif() +if (USE_PLUGIN_MANAGER) + find_package(yaml-cpp) +endif() + +set(USE_PLUGIN_MANAGER ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) @@ -213,6 +219,7 @@ target_link_libraries( Qt5::DBus Qt5::Network Qt5::Widgets + Qt5::PrintSupport ${QTSINGLEAPPLICATION_LIBRARY} QtColorWidgets diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c933bdd6f1..5bb3cd5339 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -3,6 +3,8 @@ target_sources(flameshot PRIVATE flameshotdaemon.h flameshotdbusadapter.h qguiappcurrentscreen.h + pluginmanager.h + corepluginInterface.h ) target_sources(flameshot PRIVATE @@ -11,6 +13,7 @@ target_sources(flameshot PRIVATE flameshotdaemon.cpp flameshotdbusadapter.cpp qguiappcurrentscreen.cpp + pluginmanager.cpp ) IF (WIN32) diff --git a/src/core/capturerequest.h b/src/core/capturerequest.h index ac8f885cec..ed90cc6ab1 100644 --- a/src/core/capturerequest.h +++ b/src/core/capturerequest.h @@ -27,6 +27,8 @@ class CaptureRequest PIN = 16, UPLOAD = 32, ACCEPT_ON_SELECT = 64, + PRINT_SYSTEM = 128, + SAVE_TO_PDF = 256 }; CaptureRequest(CaptureMode mode, diff --git a/src/core/corepluginInterface.h b/src/core/corepluginInterface.h new file mode 100644 index 0000000000..54f48672e8 --- /dev/null +++ b/src/core/corepluginInterface.h @@ -0,0 +1,20 @@ +#ifndef COREPLUGININTERFACE_H +#define COREPLUGININTERFACE_H + +#include + +class CorePluginInterface { +public: + virtual ~CorePluginInterface() = 0; + virtual bool load(std::map &PluginConfig) = 0; + virtual void unload() = 0; + virtual bool ImagePost(QPixmap &pixmap) = 0; + virtual bool ImageToPDFPost(QPixmap &pixmap) = 0; + virtual bool PrintPre(QPixmap &pixmap) = 0; +}; + +#define FlameshotPlugin_iid "FlameshotPlugin.CorePluginInterface" + +Q_DECLARE_INTERFACE(CorePluginInterface, FlameshotPlugin_iid) + +#endif // COREPLUGININTERFACE_H diff --git a/src/core/flameshot.cpp b/src/core/flameshot.cpp index c7eadcadb6..af564b1774 100644 --- a/src/core/flameshot.cpp +++ b/src/core/flameshot.cpp @@ -31,7 +31,15 @@ #include #include #include +#include #include +#include +#include +#include + +#ifdef USE_PLUGIN_MANAGER +#include "core/pluginmanager.h" +#endif #if defined(Q_OS_MACOS) #include @@ -352,7 +360,12 @@ void Flameshot::exportCapture(const QPixmap& capture, int tasks = req.tasks(), mode = req.captureMode(); QString path = req.path(); + QPixmap PixmapOutputBuffer(capture); + if (tasks & CR::PRINT_GEOMETRY) { +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); +#endif QByteArray byteArray; QBuffer buffer(&byteArray); QTextStream(stdout) @@ -361,9 +374,12 @@ void Flameshot::exportCapture(const QPixmap& capture, } if (tasks & CR::PRINT_RAW) { +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); +#endif QByteArray byteArray; QBuffer buffer(&byteArray); - capture.save(&buffer, "PNG"); + PixmapOutputBuffer.save(&buffer, "PNG"); QFile file; file.open(stdout, QIODevice::WriteOnly); @@ -372,19 +388,35 @@ void Flameshot::exportCapture(const QPixmap& capture, } if (tasks & CR::SAVE) { +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); +#endif if (req.path().isEmpty()) { - saveToFilesystemGUI(capture); + saveToFilesystemGUI(PixmapOutputBuffer); } else { - saveToFilesystem(capture, path); + saveToFilesystem(PixmapOutputBuffer, path); } } + if (tasks & CR::SAVE_TO_PDF) { +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->CallImageToPDFPost(PixmapOutputBuffer); +#endif + saveToPDF(PixmapOutputBuffer); + } + if (tasks & CR::COPY) { - FlameshotDaemon::copyToClipboard(capture); +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); +#endif + FlameshotDaemon::copyToClipboard(PixmapOutputBuffer); } if (tasks & CR::PIN) { - FlameshotDaemon::createPin(capture, selection); +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); +#endif + FlameshotDaemon::createPin(PixmapOutputBuffer, selection); if (mode == CR::SCREEN_MODE || mode == CR::FULLSCREEN_MODE) { AbstractLogger::info() << QObject::tr("Full screen screenshot pinned to screen"); @@ -392,6 +424,9 @@ void Flameshot::exportCapture(const QPixmap& capture, } if (tasks & CR::UPLOAD) { +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->CallImagePost(PixmapOutputBuffer); +#endif if (!ConfigHandler().uploadWithoutConfirmation()) { auto* dialog = new ImgUploadDialog(); if (dialog->exec() == QDialog::Rejected) { @@ -399,7 +434,7 @@ void Flameshot::exportCapture(const QPixmap& capture, } } - ImgUploaderBase* widget = ImgUploaderManager().uploader(capture); + ImgUploaderBase* widget = ImgUploaderManager().uploader(PixmapOutputBuffer); widget->show(); widget->activateWindow(); // NOTE: lambda can't capture 'this' because it might be destroyed later @@ -416,8 +451,68 @@ void Flameshot::exportCapture(const QPixmap& capture, }); } + if(tasks & CR::PRINT_SYSTEM) { + QPixmap pixmap = capture; +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->CallPrintPre(pixmap); +#endif + QPrinter printer; + printer.setPageOrientation(QPageLayout::Orientation::Landscape); + + QPrintPreviewDialog dialog(&printer); + dialog.setWindowFlag(Qt::WindowMinMaxButtonsHint); + dialog.setWindowTitle(tr("Print Document")); + +#if defined(Q_OS_WIN) + QToolBar *PrintPreviewToolbar = dialog.findChild(); + QList List = PrintPreviewToolbar->actions(); + int index = 0; + QSet RemoveIndex; + RemoveIndex.insert(0); + RemoveIndex.insert(1); + RemoveIndex.insert(16); + RemoveIndex.insert(17); + RemoveIndex.insert(18); + const int PrintAction = 21; + QSet RemoveList; + foreach(auto it, List) { + if(RemoveIndex.find(index) != RemoveIndex.end()) { + RemoveList.insert(it); + } + if(index == PrintAction) { + it->setIcon(QIcon(":/img/material/black/content-print.svg")); + } + index++; + } + foreach(auto it, List) { + if(RemoveList.find(it) != RemoveList.end()) { + PrintPreviewToolbar->removeAction(it); + } + } + +#endif + connect(&dialog, &QPrintPreviewDialog::paintRequested, [&](QPrinter *printer) { + QPainter painter(printer); + if((pixmap.size().width() >= printer->width()) || + (pixmap.size().height() >= printer->height())) { + pixmap = pixmap.scaled(printer->width(), printer->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else if(pixmap.size().width() >= (printer->width()/2)) { + pixmap = pixmap.scaledToWidth(printer->width(), Qt::SmoothTransformation); + if(pixmap.size().height() >= printer->height()) { + pixmap = pixmap.scaledToHeight(printer->height(), Qt::SmoothTransformation); + } + } + + QRect rect((printer->width() - pixmap.size().width()) /2, + (printer->height() - pixmap.size().height()) /2, + pixmap.size().width(), pixmap.size().height()); + painter.drawPixmap(rect, pixmap); + }); + dialog.exec(); + } + if (!(tasks & CR::UPLOAD)) { - emit captureTaken(capture); + emit captureTaken(PixmapOutputBuffer); } } diff --git a/src/core/pluginmanager.cpp b/src/core/pluginmanager.cpp new file mode 100644 index 0000000000..22aaf2e4bd --- /dev/null +++ b/src/core/pluginmanager.cpp @@ -0,0 +1,157 @@ +#ifdef USE_PLUGIN_MANAGER + +#include "pluginmanager.h" +#include +#include +#include +#include "corepluginInterface.h" + +PluginManager::PluginManager() { + +} + +PluginManager *PluginManager::getInstance() { + static PluginManager pluginManager; + qDebug() << QObject::tr("Get the plugin manager interface: ").toStdString().c_str() << &pluginManager; + return &pluginManager; +} + +void PluginManager::LoopDirsPlugins(QString Base, std::function Callback) { + QDir dirs(Base); + if(dirs.exists()) { + dirs.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); + QFileInfoList fileList = dirs.entryInfoList(); + foreach(QFileInfo fileInfo, fileList) { + if (Base != pluginDir && fileInfo.isDir()) { + QFileInfo infocheck(fileInfo.absolutePath() + PluginDefineYaml); + if(!infocheck.exists()) { + LoopDirsPlugins(fileInfo.absoluteFilePath(), Callback); + } + } else if(Base == pluginDir && fileInfo.isDir()) { + LoopDirsPlugins(fileInfo.absoluteFilePath(), Callback); + } else if(fileInfo.isFile()) { + if(fileInfo.fileName() == PluginDefineYaml) { + Callback(fileInfo.absoluteFilePath()); + } + } + } + } +} + +int PluginManager::LoadPlugins() { + int count = 0; + LoopDirsPlugins(pluginDir, [&](QString PluginInfoDefaultYaml) { + qDebug() << QObject::tr("Get Plugin Definde: ").toStdString().c_str() << PluginInfoDefaultYaml; + YAML::Node config; + try { + config = YAML::LoadFile(PluginInfoDefaultYaml.toStdString()); + } catch(std::exception &e) { + qDebug() << QObject::tr("Get Plugin Error: ").toStdString().c_str() << e.what() << PluginInfoDefaultYaml; + return; + } + + PluginInfo Info; + Info.PluginInfoFullPath = PluginInfoDefaultYaml; + Info.PluginName = QString::fromStdString(config["plugin"]["name"].as()); + if (config["plugin"]["type"].as() == "qt") { + Info.PluginType = PluginInfo::QTPlugin; + } + + QString plugin = QFileInfo(PluginInfoDefaultYaml).absolutePath() + "/" + QString::fromStdString(config["plugin"]["file"].as()); + Info.Pluginfile = plugin; + + std::map PluginConfig = config["plugin"]["config"].as>(); + + QPluginLoader *Loader = new QPluginLoader(Info.Pluginfile); + if(Loader) { + if(Loader->load()) { + CorePluginInterface *Interface = qobject_cast(Loader->instance()); + if(Interface->load(PluginConfig)) { + Info.PluginLoader = Loader; + } + } + + this->PluginLists.append(Info); + + count++; + } + + }); + qDebug() << QObject::tr("Get Plugin Count: ").toStdString().c_str() << count; + return count; +} + +bool PluginManager::UnLoadPlugins() { + foreach(auto Info, this->PluginLists) { + if(Info.PluginType == PluginInfo::QTPlugin) { + QPluginLoader *Loader = reinterpret_cast(Info.PluginLoader); + if(Loader) { + delete Loader; + Info.PluginLoader = nullptr; + } + } + } + this->PluginLists.clear(); + return false; +} + +bool PluginManager::CallImagePost(QPixmap &pixmap) { + bool Result = false; + foreach(auto Info, this->PluginLists) { + if(Info.PluginType == PluginInfo::QTPlugin) { + qDebug() << QObject::tr("Call Plugin(ImagePost): ").toStdString().c_str() << Info.PluginName; + qDebug() << QObject::tr("Call Plugin(ImagePost) YAML FileName: ").toStdString().c_str() << Info.PluginInfoFullPath; + qDebug() << QObject::tr("Call Plugin(ImagePost) Qt Plugin: ").toStdString().c_str() << Info.Pluginfile; + if (Info.PluginType == PluginInfo::QTPlugin) { + QPluginLoader *Loader = reinterpret_cast(Info.PluginLoader); + if(Loader) { + CorePluginInterface *Interface = qobject_cast(Loader->instance()); + Interface->ImagePost(pixmap); + Result = true; + } + } + } + } + return Result; +} + +bool PluginManager::CallImageToPDFPost(QPixmap &pixmap) { + bool Result = false; + foreach(auto Info, this->PluginLists) { + if(Info.PluginType == PluginInfo::QTPlugin) { + qDebug() << QObject::tr("Call Plugin(ImageToPDFPost): ").toStdString().c_str() << Info.PluginName; + qDebug() << QObject::tr("Call Plugin(ImageToPDFPost) YAML FileName: ").toStdString().c_str() << Info.PluginInfoFullPath; + qDebug() << QObject::tr("Call Plugin(ImageToPDFPost) Qt Plugin: ").toStdString().c_str() << Info.Pluginfile; + if (Info.PluginType == PluginInfo::QTPlugin) { + QPluginLoader *Loader = reinterpret_cast(Info.PluginLoader); + if(Loader) { + CorePluginInterface *Interface = qobject_cast(Loader->instance()); + Interface->ImageToPDFPost(pixmap); + Result = true; + } + } + } + } + return Result; +} + +bool PluginManager::CallPrintPre(QPixmap &pixmap) { + bool Result = false; + foreach(auto Info, this->PluginLists) { + if(Info.PluginType == PluginInfo::QTPlugin) { + qDebug() << QObject::tr("Call Plugin(PrintPre): ").toStdString().c_str() << Info.PluginName; + qDebug() << QObject::tr("Call Plugin(PrintPre) YAML FileName: ").toStdString().c_str() << Info.PluginInfoFullPath; + qDebug() << QObject::tr("Call Plugin(PrintPre) Qt Plugin: ").toStdString().c_str() << Info.Pluginfile; + if (Info.PluginType == PluginInfo::QTPlugin) { + QPluginLoader *Loader = reinterpret_cast(Info.PluginLoader); + if(Loader) { + CorePluginInterface *Interface = qobject_cast(Loader->instance()); + Interface->PrintPre(pixmap); + Result = true; + } + } + } + } + return Result; +} +#endif //USE_PLUGIN_MANAGER diff --git a/src/core/pluginmanager.h b/src/core/pluginmanager.h new file mode 100644 index 0000000000..4b32c21ef0 --- /dev/null +++ b/src/core/pluginmanager.h @@ -0,0 +1,50 @@ +#ifndef PLUGINMANAGER_H +#define PLUGINMANAGER_H + +#ifdef USE_PLUGIN_MANAGER + +#define GET_BUILD_SET(x) #x +#define BUILD_DEFINE_CONV_C_STRING(x) GET_BUILD_SET(x) + +#include +#include +#include +#include + +const QString pluginDir = BUILD_DEFINE_CONV_C_STRING(PLUGIN_DIRECTORY); + +const QString PluginDefineYaml = "plugin.yaml"; + +typedef struct _PluginInfo { + QString PluginName; + QString PluginInfoFullPath; + enum Type { + QTPlugin, + PyPlugin, /*no used*/ + LuaPlugin /*no used*/ + }PluginType; + QString Pluginfile; + void *PluginLoader; +}PluginInfo; + +class PluginManager +{ + typedef void CallbackPluginLoads(QString PluginInfoDefaultYaml); +private: + PluginManager(); +public: + static PluginManager *getInstance(); + int LoadPlugins(); + bool UnLoadPlugins(); + bool CallImagePost(QPixmap &pixmap); + bool CallImageToPDFPost(QPixmap &pixmap); + bool CallPrintPre(QPixmap &pixmap); +private: + static void LoopDirsPlugins(QString Base, std::function Callback); +private: + QList PluginLists; +}; + +#endif //USE_PLUGIN_MANAGER + +#endif // PLUGINMANAGER_H diff --git a/src/main.cpp b/src/main.cpp index 23d3157e01..b5517313a0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,6 +32,9 @@ #include #include #endif +#ifdef USE_PLUGIN_MANAGER +#include "core/pluginmanager.h" +#endif #ifdef Q_OS_LINUX // source: https://github.com/ksnip/ksnip/issues/416 @@ -126,6 +129,9 @@ void reinitializeAsQApplication(int& argc, char* argv[]) int main(int argc, char* argv[]) { +#ifdef USE_PLUGIN_MANAGER + PluginManager::getInstance()->LoadPlugins(); +#endif #ifdef Q_OS_LINUX wayland_hacks(); #endif diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index d2a629242b..6712ca6ac2 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -3,9 +3,11 @@ target_sources(flameshot PRIVATE pixelate/pixelatetool.h pixelate/pixelatetool.c target_sources(flameshot PRIVATE circle/circletool.h circle/circletool.cpp) target_sources(flameshot PRIVATE circlecount/circlecounttool.h circlecount/circlecounttool.cpp) target_sources(flameshot PRIVATE copy/copytool.h copy/copytool.cpp) +target_sources(flameshot PRIVATE print/printtool.h print/printtool.cpp) target_sources(flameshot PRIVATE exit/exittool.h exit/exittool.cpp) target_sources(flameshot PRIVATE sizeincrease/sizeincreasetool.h sizeincrease/sizeincreasetool.cpp) target_sources(flameshot PRIVATE sizedecrease/sizedecreasetool.h sizedecrease/sizedecreasetool.cpp) +target_sources(flameshot PRIVATE save-to-pdf/save-to-pdf.h save-to-pdf/save-to-pdf.cpp) target_sources( flameshot PRIVATE imgupload/storages/imgur/imguruploader.h diff --git a/src/tools/capturetool.h b/src/tools/capturetool.h index a095d61857..0783e3940b 100644 --- a/src/tools/capturetool.h +++ b/src/tools/capturetool.h @@ -41,13 +41,15 @@ class CaptureTool : public QObject TYPE_OPEN_APP = 14, TYPE_PIXELATE = 15, TYPE_REDO = 16, - TYPE_PIN = 17, - TYPE_TEXT = 18, - TYPE_CIRCLECOUNT = 19, - TYPE_SIZEINCREASE = 20, - TYPE_SIZEDECREASE = 21, - TYPE_INVERT = 22, - TYPE_ACCEPT = 23, + TYPE_PRINT = 17, + TYPE_PIN = 18, + TYPE_TEXT = 19, + TYPE_CIRCLECOUNT = 20, + TYPE_SIZEINCREASE = 21, + TYPE_SIZEDECREASE = 22, + TYPE_INVERT = 23, + TYPE_ACCEPT = 24, + TYPE_SAVE_TO_PDF = 25 }; Q_ENUM(Type); diff --git a/src/tools/print/printtool.cpp b/src/tools/print/printtool.cpp new file mode 100644 index 0000000000..b73cb23ab3 --- /dev/null +++ b/src/tools/print/printtool.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: 2017-2019 Ouyang Chunhui & Contributor + +#include "printtool.h" +#include "src/utils/screenshotsaver.h" +#include + +PrintTool::PrintTool(QObject* parent) + : AbstractActionTool(parent) +{} + +bool PrintTool::closeOnButtonPressed() const +{ + return true; +} + +QIcon PrintTool::icon(const QColor& background, bool inEditor) const +{ + Q_UNUSED(inEditor) + return QIcon(iconPath(background) + "content-print.svg"); +} +QString PrintTool::name() const +{ + return tr("Print"); +} + +CaptureTool::Type PrintTool::type() const +{ + return CaptureTool::TYPE_PRINT; +} + +QString PrintTool::description() const +{ + return tr("Print"); +} + +CaptureTool* PrintTool::copy(QObject* parent) +{ + return new PrintTool(parent); +} + +void PrintTool::pressed(CaptureContext& context) +{ + emit requestAction(REQ_CLEAR_SELECTION); + context.request.addTask(CaptureRequest::PRINT_SYSTEM); + emit requestAction(REQ_CAPTURE_DONE_OK); + emit requestAction(REQ_CLOSE_GUI); +} diff --git a/src/tools/print/printtool.h b/src/tools/print/printtool.h new file mode 100644 index 0000000000..42ae384e7b --- /dev/null +++ b/src/tools/print/printtool.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: 2017-2019 Ouyang Chunhui & Contributor + +#pragma once + +#include "src/tools/abstractactiontool.h" + +class PrintTool : public AbstractActionTool +{ + Q_OBJECT +public: + explicit PrintTool(QObject* parent = nullptr); + bool closeOnButtonPressed() const override; + + QIcon icon(const QColor& background, bool inEditor) const override; + QString name() const override; + QString description() const override; + + CaptureTool* copy(QObject* parent = nullptr) override; + +protected: + CaptureTool::Type type() const override; + +public slots: + void pressed(CaptureContext& context) override; +}; diff --git a/src/tools/save-to-pdf/save-to-pdf.cpp b/src/tools/save-to-pdf/save-to-pdf.cpp new file mode 100644 index 0000000000..46fbc7e639 --- /dev/null +++ b/src/tools/save-to-pdf/save-to-pdf.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: 2017-2019 Ouyang Chunhui & Contributor + +#include "save-to-pdf.h" +#include "src/utils/screenshotsaver.h" +#include + +SaveToPDFTool::SaveToPDFTool(QObject* parent) + : AbstractActionTool(parent) +{} + +bool SaveToPDFTool::closeOnButtonPressed() const +{ + return true; +} + +QIcon SaveToPDFTool::icon(const QColor& background, bool inEditor) const +{ + Q_UNUSED(inEditor) + return QIcon(iconPath(background) + "save-to-pdf.svg"); +} +QString SaveToPDFTool::name() const +{ + return tr("Save To PDF"); +} + +CaptureTool::Type SaveToPDFTool::type() const +{ + return CaptureTool::TYPE_PRINT; +} + +QString SaveToPDFTool::description() const +{ + return tr("Save To PDF"); +} + +CaptureTool* SaveToPDFTool::copy(QObject* parent) +{ + return new SaveToPDFTool(parent); +} + +void SaveToPDFTool::pressed(CaptureContext& context) +{ + emit requestAction(REQ_CLEAR_SELECTION); + context.request.addTask(CaptureRequest::SAVE_TO_PDF); + emit requestAction(REQ_CAPTURE_DONE_OK); + emit requestAction(REQ_CLOSE_GUI); +} diff --git a/src/tools/save-to-pdf/save-to-pdf.h b/src/tools/save-to-pdf/save-to-pdf.h new file mode 100644 index 0000000000..97c35f5351 --- /dev/null +++ b/src/tools/save-to-pdf/save-to-pdf.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: 2017-2019 Ouyang Chunhui & Contributor + +#pragma once + +#include "src/tools/abstractactiontool.h" + +class SaveToPDFTool : public AbstractActionTool +{ + Q_OBJECT +public: + explicit SaveToPDFTool(QObject* parent = nullptr); + bool closeOnButtonPressed() const override; + + QIcon icon(const QColor& background, bool inEditor) const override; + QString name() const override; + QString description() const override; + + CaptureTool* copy(QObject* parent = nullptr) override; + +protected: + CaptureTool::Type type() const override; + +public slots: + void pressed(CaptureContext& context) override; +}; diff --git a/src/tools/toolfactory.cpp b/src/tools/toolfactory.cpp index 98ed0ab3d7..5910fd821f 100644 --- a/src/tools/toolfactory.cpp +++ b/src/tools/toolfactory.cpp @@ -20,9 +20,11 @@ #include "rectangle/rectangletool.h" #include "redo/redotool.h" #include "save/savetool.h" +#include "save-to-pdf/save-to-pdf.h" #include "selection/selectiontool.h" #include "sizedecrease/sizedecreasetool.h" #include "sizeincrease/sizeincreasetool.h" +#include "print/printtool.h" #include "text/texttool.h" #include "undo/undotool.h" @@ -48,6 +50,7 @@ CaptureTool* ToolFactory::CreateTool(CaptureTool::Type t, QObject* parent) if_TYPE_return_TOOL(TYPE_UNDO, UndoTool); if_TYPE_return_TOOL(TYPE_COPY, CopyTool); if_TYPE_return_TOOL(TYPE_SAVE, SaveTool); + if_TYPE_return_TOOL(TYPE_SAVE_TO_PDF, SaveToPDFTool); if_TYPE_return_TOOL(TYPE_EXIT, ExitTool); if_TYPE_return_TOOL(TYPE_IMAGEUPLOADER, ImgUploaderTool); #if !defined(Q_OS_MACOS) @@ -55,6 +58,7 @@ CaptureTool* ToolFactory::CreateTool(CaptureTool::Type t, QObject* parent) #endif if_TYPE_return_TOOL(TYPE_PIXELATE, PixelateTool); if_TYPE_return_TOOL(TYPE_REDO, RedoTool); + if_TYPE_return_TOOL(TYPE_PRINT, PrintTool); if_TYPE_return_TOOL(TYPE_PIN, PinTool); if_TYPE_return_TOOL(TYPE_TEXT, TextTool); if_TYPE_return_TOOL(TYPE_CIRCLECOUNT, CircleCountTool); diff --git a/src/utils/confighandler.cpp b/src/utils/confighandler.cpp index 485fb26575..91a87007d0 100644 --- a/src/utils/confighandler.cpp +++ b/src/utils/confighandler.cpp @@ -142,6 +142,7 @@ static QMap> recognizedShortcuts = { SHORTCUT("TYPE_UNDO" , "Ctrl+Z" ), SHORTCUT("TYPE_COPY" , "Ctrl+C" ), SHORTCUT("TYPE_SAVE" , "Ctrl+S" ), + SHORTCUT("TYPE_SAVE_TO_PDF" , ), SHORTCUT("TYPE_ACCEPT" , "Return" ), SHORTCUT("TYPE_EXIT" , "Ctrl+Q" ), SHORTCUT("TYPE_IMAGEUPLOADER" , ), @@ -179,6 +180,7 @@ static QMap> recognizedShortcuts = { SHORTCUT("TYPE_SIZEINCREASE" , ), SHORTCUT("TYPE_SIZEDECREASE" , ), SHORTCUT("TYPE_CIRCLECOUNT" , ), + SHORTCUT("TYPE_PRINT", ) }; // clang-format on diff --git a/src/utils/screenshotsaver.cpp b/src/utils/screenshotsaver.cpp index f7f5a7102b..5932681583 100644 --- a/src/utils/screenshotsaver.cpp +++ b/src/utils/screenshotsaver.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#ifdef USE_PLUGIN_MANAGER +#include "core/pluginmanager.h" +#endif #if defined(Q_OS_MACOS) #include "src/widgets/capture/capturewidget.h" #endif @@ -101,6 +105,23 @@ QString ShowSaveFileDialog(const QString& title, const QString& directory) } } +QString ShowSaveToPDFDialog(const QString& title, const QString& directory) +{ + QFileDialog dialog(nullptr, title, directory); + dialog.setAcceptMode(QFileDialog::AcceptSave); + + // Build string list of supported image formats + QStringList mimeTypeList; + mimeTypeList.append("application/pdf"); + dialog.setMimeTypeFilters(mimeTypeList); + if (dialog.exec() == QDialog::Accepted) { + return dialog.selectedFiles().constFirst(); + } else { + return {}; + } +} + + void saveToClipboardMime(const QPixmap& capture, const QString& imageType) { QByteArray array; @@ -168,6 +189,49 @@ void saveToClipboard(const QPixmap& capture) } } +bool saveToPDF(const QPixmap& capture) { + bool okay = false; + QString savePath; + ConfigHandler config; + savePath = QDir::toNativeSeparators( + ShowSaveToPDFDialog(QObject::tr("Save screenshot To PDF"), savePath)); + if(savePath.endsWith(".pdf", Qt::CaseInsensitive)) { + QPrinter printer(QPrinter::HighResolution); + printer.setOutputFormat(QPrinter::PdfFormat); + printer.setPageOrientation(QPageLayout::Landscape); + printer.setPageSize(QPageSize::A4); + printer.setOutputFileName(savePath); + QPainter painter(&printer); + QPixmap new_capture = capture.scaled(printer.width(), printer.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + QRect rect(0, 0, new_capture.size().width(), new_capture.size().height()); + painter.drawPixmap(rect, new_capture); + okay = true; + } + + if(okay) { + QString pathNoFile = + savePath.left(savePath.lastIndexOf(QDir::separator())); + + ConfigHandler().setSavePath(pathNoFile); + + QString msg = QObject::tr("Capture saved as ") + savePath; + AbstractLogger().attachNotificationPath(savePath) << msg; + + if (config.copyPathAfterSave()) { + FlameshotDaemon::copyToClipboard( + savePath, QObject::tr("Path copied to clipboard as ") + savePath); + } + } else { + QString msg = QObject::tr("Error trying to save as ") + savePath; + QMessageBox saveErrBox( + QMessageBox::Warning, QObject::tr("Save Error"), msg); + saveErrBox.setWindowIcon(QIcon(GlobalValues::iconPath())); + saveErrBox.exec(); + } + + return okay; +} + bool saveToFilesystemGUI(const QPixmap& capture) { bool okay = false; diff --git a/src/utils/screenshotsaver.h b/src/utils/screenshotsaver.h index 9face3468b..a1675eadb9 100644 --- a/src/utils/screenshotsaver.h +++ b/src/utils/screenshotsaver.h @@ -11,6 +11,8 @@ bool saveToFilesystem(const QPixmap& capture, const QString& path, const QString& messagePrefix = ""); QString ShowSaveFileDialog(const QString& title, const QString& directory); +QString ShowSaveToPDFDialog(const QString& title, const QString& directory); void saveToClipboardMime(const QPixmap& capture, const QString& imageType); void saveToClipboard(const QPixmap& capture); bool saveToFilesystemGUI(const QPixmap& capture); +bool saveToPDF(const QPixmap& capture); diff --git a/src/widgets/capture/capturetoolbutton.cpp b/src/widgets/capture/capturetoolbutton.cpp index bc51eb7272..be211d1db3 100644 --- a/src/widgets/capture/capturetoolbutton.cpp +++ b/src/widgets/capture/capturetoolbutton.cpp @@ -146,17 +146,18 @@ static std::map buttonTypeOrder { CaptureTool::TYPE_SELECTIONINDICATOR, 11 }, { CaptureTool::TYPE_MOVESELECTION, 12 }, { CaptureTool::TYPE_UNDO, 13 }, { CaptureTool::TYPE_REDO, 14 }, { CaptureTool::TYPE_COPY, 15 }, - { CaptureTool::TYPE_SAVE, 16 }, { CaptureTool::TYPE_IMAGEUPLOADER, 17 }, - { CaptureTool::TYPE_ACCEPT, 18 }, + { CaptureTool::TYPE_SAVE, 16 }, { CaptureTool::TYPE_SAVE_TO_PDF, 17}, + { CaptureTool::TYPE_PRINT, 18}, { CaptureTool::TYPE_IMAGEUPLOADER, 29 }, + { CaptureTool::TYPE_ACCEPT, 20 }, #if !defined(Q_OS_MACOS) - { CaptureTool::TYPE_OPEN_APP, 19 }, { CaptureTool::TYPE_EXIT, 20 }, - { CaptureTool::TYPE_PIN, 21 }, + { CaptureTool::TYPE_OPEN_APP, 21 }, { CaptureTool::TYPE_EXIT, 22 }, + { CaptureTool::TYPE_PIN, 23 }, #else - { CaptureTool::TYPE_EXIT, 19 }, { CaptureTool::TYPE_PIN, 20 }, + { CaptureTool::TYPE_EXIT, 21 }, { CaptureTool::TYPE_PIN, 22 }, #endif - { CaptureTool::TYPE_SIZEINCREASE, 22 }, - { CaptureTool::TYPE_SIZEDECREASE, 23 }, + { CaptureTool::TYPE_SIZEINCREASE, 24 }, + { CaptureTool::TYPE_SIZEDECREASE, 25 }, }; int CaptureToolButton::getPriorityByButton(CaptureTool::Type b) @@ -174,7 +175,8 @@ QList CaptureToolButton::iterableButtonTypes = { CaptureTool::TYPE_CIRCLECOUNT, CaptureTool::TYPE_PIXELATE, CaptureTool::TYPE_MOVESELECTION, CaptureTool::TYPE_UNDO, CaptureTool::TYPE_REDO, CaptureTool::TYPE_COPY, - CaptureTool::TYPE_SAVE, CaptureTool::TYPE_EXIT, + CaptureTool::TYPE_SAVE, CaptureTool::TYPE_SAVE_TO_PDF, + CaptureTool::TYPE_PRINT, CaptureTool::TYPE_EXIT, CaptureTool::TYPE_IMAGEUPLOADER, #if !defined(Q_OS_MACOS) CaptureTool::TYPE_OPEN_APP, diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 49ebff9720..9245694680 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -296,6 +296,7 @@ void CaptureWidget::initButtons() // Remove irrelevant buttons from both lists for (auto* buttonList : { &allButtonTypes, &visibleButtonTypes }) { buttonList->removeOne(CaptureTool::TYPE_SAVE); + buttonList->removeOne(CaptureTool::TYPE_SAVE_TO_PDF); buttonList->removeOne(CaptureTool::TYPE_COPY); buttonList->removeOne(CaptureTool::TYPE_IMAGEUPLOADER); buttonList->removeOne(CaptureTool::TYPE_OPEN_APP);