From 650f7c04d0bc54b70ae775b8e448e8e6fef1b82d Mon Sep 17 00:00:00 2001 From: Ouyang Chunhui Date: Fri, 5 Jul 2024 17:31:35 +0800 Subject: [PATCH 1/3] 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 | 21 + src/core/flameshot.cpp | 119 +- src/core/pluginmanager.cpp | 205 +++ src/core/pluginmanager.h | 57 + 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 | 68 + src/utils/screenshotsaver.h | 2 + src/widgets/capture/capturetoolbutton.cpp | 18 +- src/widgets/capture/capturewidget.cpp | 1 + 27 files changed, 2022 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..bb3e8a7631 --- /dev/null +++ b/src/core/corepluginInterface.h @@ -0,0 +1,21 @@ +#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..0550dc222e 100644 --- a/src/core/flameshot.cpp +++ b/src/core/flameshot.cpp @@ -27,11 +27,19 @@ #include #include #include +#include #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,8 @@ 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 +452,77 @@ 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..3517b83c27 --- /dev/null +++ b/src/core/pluginmanager.cpp @@ -0,0 +1,205 @@ +#ifdef USE_PLUGIN_MANAGER + +#include "pluginmanager.h" +#include "corepluginInterface.h" +#include +#include +#include + +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..553c96c146 --- /dev/null +++ b/src/core/pluginmanager.h @@ -0,0 +1,57 @@ +#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..b023fb724f 100644 --- a/src/tools/toolfactory.cpp +++ b/src/tools/toolfactory.cpp @@ -17,8 +17,10 @@ #include "pencil/penciltool.h" #include "pin/pintool.h" #include "pixelate/pixelatetool.h" +#include "print/printtool.h" #include "rectangle/rectangletool.h" #include "redo/redotool.h" +#include "save-to-pdf/save-to-pdf.h" #include "save/savetool.h" #include "selection/selectiontool.h" #include "sizedecrease/sizedecreasetool.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..235e0f6207 100644 --- a/src/utils/screenshotsaver.cpp +++ b/src/utils/screenshotsaver.cpp @@ -21,8 +21,12 @@ #include #include #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,22 @@ 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 +188,54 @@ 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..88b21fbadd 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); From 66327f975a482428e4244f97514c38f5e26814bc Mon Sep 17 00:00:00 2001 From: Ouyang Chunhui Date: Fri, 5 Jul 2024 17:56:24 +0800 Subject: [PATCH 2/3] PDF and printer support are not enabled by default This is to counter PR checks, because it seems that the PR's qt environment does not support some specific parameters of this function - the latest version of qt5 compiles fine on Linux Signed-off-by: Ouyang Chunhui --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 16 +++++++++++++--- src/core/flameshot.cpp | 9 +++++++++ src/utils/screenshotsaver.cpp | 5 +++++ src/widgets/capture/capturewidget.cpp | 6 ++++++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a49d96a7f6..83580857b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,7 @@ option(USE_LAUNCHER_ABSOLUTE_PATH "Use absolute path for the desktop launcher" O 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) +option(USE_PRINTER_SUPPORT "Enable printer and PDF output support" OFF) if (USE_PLUGIN_MANAGER) set(PLUGIN_DIRECTORY "app_plugins" CACHE PATH "Setting the Plugin Manager Plugin Directory") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9a3078d7ad..507f0aa35a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,8 +8,11 @@ find_package( Network Svg DBus - LinguistTools - PrintSupport) + LinguistTools) + +if (USE_PRINTER_SUPPORT) + find_package(PrintSupport) +endif() if (USE_WAYLAND_CLIPBOARD) find_package(KF5GuiAddons) @@ -219,12 +222,15 @@ target_link_libraries( Qt5::DBus Qt5::Network Qt5::Widgets - Qt5::PrintSupport ${QTSINGLEAPPLICATION_LIBRARY} QtColorWidgets ) +if (USE_PRINTER_SUPPORT) + target_link_libraries(flameshot Qt5::PrintSupport) +endif() + if (USE_WAYLAND_CLIPBOARD) if(!USE_WAYLAND_GRIM) message(WARNING "You activated the USE_WAYLAND_CLIPBOARD option, but did not activate the USE_WAYLAND_GRIM option. Flameshot will use the dbus protocol to support wayland. If you use wlroots-based wayland, it is recommended to enable USE_WAYLAND_GRIM") @@ -237,6 +243,10 @@ if (USE_WAYLAND_GRIM) target_compile_definitions(flameshot PRIVATE USE_WAYLAND_GRIM=1) endif() +if (USE_PRINTER_SUPPORT) + target_compile_definitions(flameshot PRIVATE USE_PRINTER_SUPPORT=1) +endif() + if (APPLE) set(MACOSX_BUNDLE_IDENTIFIER "org.flameshot") set_target_properties( diff --git a/src/core/flameshot.cpp b/src/core/flameshot.cpp index 0550dc222e..ed0031bf44 100644 --- a/src/core/flameshot.cpp +++ b/src/core/flameshot.cpp @@ -34,8 +34,11 @@ #include #include #include + +#ifdef USE_PRINTER_SUPPORT #include #include +#endif #ifdef USE_PLUGIN_MANAGER #include "core/pluginmanager.h" @@ -398,12 +401,15 @@ void Flameshot::exportCapture(const QPixmap& capture, } } +#ifdef USE_PRINTER_SUPPORT + if (tasks & CR::SAVE_TO_PDF) { #ifdef USE_PLUGIN_MANAGER PluginManager::getInstance()->CallImageToPDFPost(PixmapOutputBuffer); #endif saveToPDF(PixmapOutputBuffer); } +#endif if (tasks & CR::COPY) { #ifdef USE_PLUGIN_MANAGER @@ -452,6 +458,8 @@ void Flameshot::exportCapture(const QPixmap& capture, }); } +#ifdef USE_PRINTER_SUPPORT + if (tasks & CR::PRINT_SYSTEM) { QPixmap pixmap = capture; #ifdef USE_PLUGIN_MANAGER @@ -520,6 +528,7 @@ void Flameshot::exportCapture(const QPixmap& capture, }); dialog.exec(); } +#endif if (!(tasks & CR::UPLOAD)) { emit captureTaken(PixmapOutputBuffer); diff --git a/src/utils/screenshotsaver.cpp b/src/utils/screenshotsaver.cpp index 235e0f6207..402793dbc0 100644 --- a/src/utils/screenshotsaver.cpp +++ b/src/utils/screenshotsaver.cpp @@ -21,7 +21,9 @@ #include #include #include +#ifdef USE_PRINTER_SUPPORT #include +#endif #include #include #ifdef USE_PLUGIN_MANAGER @@ -188,6 +190,7 @@ void saveToClipboard(const QPixmap& capture) } } +#ifdef USE_PRINTER_SUPPORT bool saveToPDF(const QPixmap& capture) { bool okay = false; @@ -236,6 +239,8 @@ bool saveToPDF(const QPixmap& capture) return okay; } +#endif + bool saveToFilesystemGUI(const QPixmap& capture) { bool okay = false; diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 9245694680..04cb90b567 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -303,6 +303,12 @@ void CaptureWidget::initButtons() buttonList->removeOne(CaptureTool::TYPE_PIN); } } + +#ifdef USE_PRINTER_SUPPORT + buttonList->removeOne(CaptureTool::TYPE_SAVE_TO_PDF); + buttonList->removeOne(CaptureTool::TYPE_PRINT); +#endif + QVector vectorButtons; // Add all buttons but hide those that were disabled in the Interface config From d8d9842f7fa29240fed67490c82fc3a318342fb4 Mon Sep 17 00:00:00 2001 From: Ouyang Chunhui Date: Thu, 11 Jul 2024 02:31:56 +0800 Subject: [PATCH 3/3] This is experimental Since the plugin manager is an experimental feature, the compilation flag is turned off by default. Signed-off-by: Ouyang Chunhui --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 83580857b9..6bdc8b26df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ 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_PLUGIN_MANAGER "Activate the Plugin Manager" OFF) option(USE_PRINTER_SUPPORT "Enable printer and PDF output support" OFF) if (USE_PLUGIN_MANAGER)