├── example ├── Resources │ ├── icons │ │ ├── ok.png │ │ ├── clear.png │ │ ├── close.png │ │ ├── copy.png │ │ ├── cut.png │ │ ├── error.png │ │ ├── file.png │ │ ├── find.png │ │ ├── fonts.png │ │ ├── info.png │ │ ├── new.png │ │ ├── open.png │ │ ├── paste.png │ │ ├── pdf.png │ │ ├── prefs.png │ │ ├── print.png │ │ ├── quit.png │ │ ├── redo.png │ │ ├── save.png │ │ ├── stop.png │ │ ├── text.png │ │ ├── undo.png │ │ ├── delete.png │ │ ├── delete2.png │ │ ├── rename.png │ │ ├── replace.png │ │ ├── saveas.png │ │ ├── search.png │ │ ├── warning.png │ │ ├── wrench.png │ │ ├── arrow-down.png │ │ ├── arrow-left.png │ │ ├── arrow-up.png │ │ ├── exit-dfree.png │ │ ├── goto-dfree.png │ │ ├── properties.png │ │ ├── question.png │ │ ├── selectall.png │ │ ├── settings.png │ │ ├── arrow-right.png │ │ ├── open-recent.png │ │ ├── checkbox_checked.png │ │ ├── document-save-all.png │ │ └── checkbox_unchecked.png │ └── MiniPdf.qrc ├── TODO ├── Core │ ├── StyleManager │ │ ├── StyleManager.hpp │ │ └── StyleManager.cpp │ └── Tools │ │ ├── Tools.hpp │ │ └── Tools.cpp ├── Gui │ ├── Widgets │ │ ├── FileDialog │ │ │ ├── FileDialog.hpp │ │ │ └── FileDialog.cpp │ │ ├── Settings │ │ │ ├── Settings.hpp │ │ │ └── Settings.cpp │ │ ├── TabWidget │ │ │ ├── TabWidget.hpp │ │ │ └── TabWidget.cpp │ │ ├── Buttons │ │ │ ├── ActionButtons.hpp │ │ │ ├── ButtonSet.hpp │ │ │ ├── ActionButtons.cpp │ │ │ └── ButtonSet.cpp │ │ ├── RecentFiles │ │ │ ├── RecentFilesWidget.hpp │ │ │ └── RecentFilesWidget.cpp │ │ └── Misc │ │ │ ├── GuiWidgets.hpp │ │ │ └── GuiWidgets.cpp │ ├── Dialogs │ │ ├── Dialog.hpp │ │ ├── Dialog.cpp │ │ ├── MessageDialog.hpp │ │ └── MessageDialog.cpp │ ├── UI │ │ ├── MiniPdf.hpp │ │ └── MiniPdf.cpp │ └── Application │ │ ├── qtlockedfile.hpp │ │ ├── qtlocalpeer.hpp │ │ ├── MPApplication.hpp │ │ ├── qtlockedfile_unix.cpp │ │ ├── qtlocalpeer.cpp │ │ ├── qtlockedfile.cpp │ │ └── MPApplication.cpp ├── Global.hpp ├── Main.cpp └── CMakeLists.txt ├── .gitignore ├── .travis.yml ├── ChangeLog ├── TODO ├── lib ├── PdfPrinter.hpp ├── Global.hpp ├── Document │ ├── RendererImpl.hpp │ ├── Renderer.hpp │ ├── RenderOptions.hpp │ ├── Navigation.cpp │ ├── Document.hpp │ ├── Document.cpp │ ├── Navigation.hpp │ └── Renderer.cpp ├── CMakeLists.txt ├── Poppler │ ├── PopplerDocument.hpp │ └── PopplerDocument.cpp ├── MuPdf │ ├── MuPdfDocument.hpp │ └── MuPdfDocument.cpp ├── View │ ├── ViewImpl.hpp │ ├── ViewWidgets.hpp │ └── View.hpp └── PdfPrinter.cpp └── README.md /example/Resources/icons/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/ok.png -------------------------------------------------------------------------------- /example/Resources/icons/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/clear.png -------------------------------------------------------------------------------- /example/Resources/icons/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/close.png -------------------------------------------------------------------------------- /example/Resources/icons/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/copy.png -------------------------------------------------------------------------------- /example/Resources/icons/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/cut.png -------------------------------------------------------------------------------- /example/Resources/icons/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/error.png -------------------------------------------------------------------------------- /example/Resources/icons/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/file.png -------------------------------------------------------------------------------- /example/Resources/icons/find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/find.png -------------------------------------------------------------------------------- /example/Resources/icons/fonts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/fonts.png -------------------------------------------------------------------------------- /example/Resources/icons/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/info.png -------------------------------------------------------------------------------- /example/Resources/icons/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/new.png -------------------------------------------------------------------------------- /example/Resources/icons/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/open.png -------------------------------------------------------------------------------- /example/Resources/icons/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/paste.png -------------------------------------------------------------------------------- /example/Resources/icons/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/pdf.png -------------------------------------------------------------------------------- /example/Resources/icons/prefs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/prefs.png -------------------------------------------------------------------------------- /example/Resources/icons/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/print.png -------------------------------------------------------------------------------- /example/Resources/icons/quit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/quit.png -------------------------------------------------------------------------------- /example/Resources/icons/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/redo.png -------------------------------------------------------------------------------- /example/Resources/icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/save.png -------------------------------------------------------------------------------- /example/Resources/icons/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/stop.png -------------------------------------------------------------------------------- /example/Resources/icons/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/text.png -------------------------------------------------------------------------------- /example/Resources/icons/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/undo.png -------------------------------------------------------------------------------- /example/Resources/icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/delete.png -------------------------------------------------------------------------------- /example/Resources/icons/delete2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/delete2.png -------------------------------------------------------------------------------- /example/Resources/icons/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/rename.png -------------------------------------------------------------------------------- /example/Resources/icons/replace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/replace.png -------------------------------------------------------------------------------- /example/Resources/icons/saveas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/saveas.png -------------------------------------------------------------------------------- /example/Resources/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/search.png -------------------------------------------------------------------------------- /example/Resources/icons/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/warning.png -------------------------------------------------------------------------------- /example/Resources/icons/wrench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/wrench.png -------------------------------------------------------------------------------- /example/Resources/icons/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/arrow-down.png -------------------------------------------------------------------------------- /example/Resources/icons/arrow-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/arrow-left.png -------------------------------------------------------------------------------- /example/Resources/icons/arrow-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/arrow-up.png -------------------------------------------------------------------------------- /example/Resources/icons/exit-dfree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/exit-dfree.png -------------------------------------------------------------------------------- /example/Resources/icons/goto-dfree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/goto-dfree.png -------------------------------------------------------------------------------- /example/Resources/icons/properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/properties.png -------------------------------------------------------------------------------- /example/Resources/icons/question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/question.png -------------------------------------------------------------------------------- /example/Resources/icons/selectall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/selectall.png -------------------------------------------------------------------------------- /example/Resources/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/settings.png -------------------------------------------------------------------------------- /example/Resources/icons/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/arrow-right.png -------------------------------------------------------------------------------- /example/Resources/icons/open-recent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/open-recent.png -------------------------------------------------------------------------------- /example/Resources/icons/checkbox_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/checkbox_checked.png -------------------------------------------------------------------------------- /example/Resources/icons/document-save-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/document-save-all.png -------------------------------------------------------------------------------- /example/Resources/icons/checkbox_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcusbritanicus/PdfWidget/HEAD/example/Resources/icons/checkbox_unchecked.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | trial.pdf 2 | Makefile* 3 | pdfwidget* 4 | libpdfwidget* 5 | .qmake.stash 6 | minipdf* 7 | build 8 | mupdf/build 9 | acrobat-flat.png 10 | .directory 11 | References 12 | .build 13 | -------------------------------------------------------------------------------- /example/TODO: -------------------------------------------------------------------------------- 1 | MiniPDF v1 - ToDo 2 | ================= 3 | 4 | - Auto Reload changed files [ G ] 5 | - Add print and props actions [ G ] 6 | 7 | [G] - Gui changes 8 | [M] - Option to be added to Menu 9 | [S] - Option to be added in Settings dialog 10 | -------------------------------------------------------------------------------- /example/Core/StyleManager/StyleManager.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * StyleManager.hpp - StyleManager.cpp Header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | class StyleManager { 12 | 13 | public: 14 | static QString getStyleSheet( QString ); 15 | static QPalette getPalette(); 16 | static QPalette transparentPalette(); 17 | }; 18 | -------------------------------------------------------------------------------- /example/Gui/Widgets/FileDialog/FileDialog.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * FileDialog.hpp - MiniPDF's FileDialog class header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | 11 | class FileDialog : public QFileDialog { 12 | Q_OBJECT 13 | 14 | public: 15 | static QStringList getOpenFileNames( QWidget *parent, QString location ); 16 | static QString getSaveFileName( QWidget *parent, QString location ); 17 | }; 18 | -------------------------------------------------------------------------------- /example/Global.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Global.hpp - Globally used header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | static QSettings settings( "MiniPDF", "MiniPDF" ); 22 | static QMimeDatabase mimeDb; 23 | -------------------------------------------------------------------------------- /example/Core/Tools/Tools.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Tools.hpp - Tools.cpp header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | /* Qt4 Equivalent of linux dirname and basename */ 12 | QString dirName( QString path ); 13 | QString baseName( QString path ); 14 | 15 | /* MimeType from QMimeDatabase */ 16 | QString getMimeType( QString path ); 17 | QPixmap getPixmap( QString path ); 18 | 19 | qint64 getSize( QString path ); 20 | mode_t getMode( QString path ); 21 | 22 | QString formatSize( qint64 ); 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: gcc 3 | sudo: require 4 | dist: trusty 5 | 6 | before_install: 7 | - sudo apt-get update -qq 8 | 9 | install: 10 | - sudo apt-get -y install qtbase5-dev qtbase5-dev-tools libpoppler-qt5-dev 11 | 12 | script: 13 | - echo $(nproc) 14 | - qmake -qt5 CONFIG+=release PREFIX=/usr 15 | - make -j$(nproc) 16 | - make INSTALL_ROOT=appdir -j$(nproc) install 17 | 18 | branches: 19 | except: 20 | - # Do not build tags that we create when we upload to GitHub Releases 21 | - /^(?i:continuous)/ 22 | -------------------------------------------------------------------------------- /example/Gui/Widgets/Settings/Settings.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * wSettings.hpp - MiniPDF's Settings Class Header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | 11 | class wSettings : public QDialog { 12 | Q_OBJECT 13 | 14 | public : 15 | wSettings( QWidget *parent = 0 ); 16 | void setFont( const QFont & ); 17 | 18 | QLabel *fontLbl; 19 | QPushButton *fontBtn; 20 | 21 | private : 22 | void setupGUI(); 23 | void setWindowProperties(); 24 | 25 | private slots : 26 | void chooseFont(); 27 | 28 | signals : 29 | void fontSet(); 30 | }; 31 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | PdfWidget v0.0.3 2 | - PdfDocument no supports two backends, Poppler and MuPdf 3 | - Encryption check enabled 4 | - PdfView has been refined 5 | - Supported view modes are SinglePage/DoublePage/FitPageToWidth/FitPageToHeight 6 | - Supported layout modes are Continuous layout 7 | 8 | PdfWidget v0.0.2 9 | - PdfDocument refined 10 | - PdfView rewritten to support Single/Double/Book + Continuous/Discrete views 11 | 12 | PdfWidget v0.0.1 13 | - Initial attempt at making a simple PDFWidget for Qt 14 | - Feature: Zooming of pages (25% of the current view width to 400% of the current view width) 15 | -------------------------------------------------------------------------------- /example/Gui/Dialogs/Dialog.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Dialog.hpp - Dialog.cpp header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | #include "GuiWidgets.hpp" 11 | 12 | class Dialog : public QDialog { 13 | Q_OBJECT 14 | 15 | public: 16 | Dialog( QWidget *parent = 0 ); 17 | 18 | void setLayout( QLayout* ); 19 | void setDialogTitle( QString ); 20 | void setDialogIcon( QIcon ); 21 | 22 | private: 23 | void setupGUI(); 24 | void setupActions(); 25 | void setupDialogProperties(); 26 | 27 | protected: 28 | void closeEvent( QCloseEvent* ); 29 | 30 | Q_SIGNALS: 31 | void closed(); 32 | }; 33 | -------------------------------------------------------------------------------- /example/Gui/Widgets/TabWidget/TabWidget.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * TabWidget.hpp - MiniPDF's TabWidget Header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | #include "GuiWidgets.hpp" 11 | 12 | class TabWidget : public QTabWidget { 13 | Q_OBJECT 14 | 15 | public : 16 | TabWidget( QWidget *parent = 0 ); 17 | 18 | void removeTab( int ); 19 | void setTabTextColor( int, QColor ); 20 | 21 | private slots: 22 | void nextTab(); 23 | void prevTab(); 24 | 25 | void moveTabRight(); 26 | void moveTabLeft(); 27 | 28 | void moveTabFirst(); 29 | void moveTabLast(); 30 | 31 | Q_SIGNALS: 32 | void open(); 33 | }; 34 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | PdfWidget 0.0.3 2 | 3 | PdfDocument 4 | ✓ Backends 5 | ✓ MuPdf Backend 6 | ✓ Poppler Backend 7 | 8 | ✓ Supported Features 9 | - Render page to image at multiple dpi values 10 | - Extract text from a page 11 | - Check for password 12 | 13 | PdfView 14 | ◐ ViewModes: 15 | ✓ SinglePageView 16 | ✓ DoublePageView 17 | ✓ FitPageToWidth 18 | ✓ FitPageToHeight 19 | □ BookView 20 | 21 | ◐ LayoutMode: 22 | □ DiscreetMode (SinglePage) 23 | ✓ Continuous Mode 24 | 25 | □ Rotation of pages 26 | 27 | 28 | Note: 29 | ✍ - Work in progress 30 | □ - Work to be started 31 | ✓ - Work Completed 32 | ✗ - Not working on this 33 | ◐ - Partially complete 34 | -------------------------------------------------------------------------------- /lib/PdfPrinter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * PdfPrinter.hpp - PDF printing class header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #if QT_VERSION >= 0x050000 13 | #include 14 | #endif 15 | 16 | class PdfPrinter : public QDialog { 17 | Q_OBJECT 18 | 19 | public: 20 | PdfPrinter( QString path, int curPg = 1, QWidget *parent = NULL ); 21 | 22 | private: 23 | void setupUI(); 24 | 25 | QComboBox *printersCB; 26 | QRadioButton *pageRangeAllRB, *pageRangeCustomRB, *pageRangeCurrentRB; 27 | QLineEdit *pageCustomLE; 28 | QRadioButton *singleRB, *doubleRB; 29 | QRadioButton *potraitRB, *landscapeRB; 30 | QSpinBox *copiesSB; 31 | QPushButton *cancelBtn, *printBtn; 32 | 33 | QString mPdfDoc; 34 | int mCurrentPage; 35 | 36 | private Q_SLOTS: 37 | void print(); 38 | }; 39 | -------------------------------------------------------------------------------- /example/Gui/Widgets/Buttons/ActionButtons.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ActionButtons.cpp - Minimize/Maximize/Close Button Widget Class 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | 11 | class ActionButtons : public QWidget { 12 | Q_OBJECT 13 | 14 | public: 15 | ActionButtons( bool, bool, bool ); 16 | ~ActionButtons(); 17 | 18 | private: 19 | QPainter *painter; 20 | 21 | bool maxBtnEnabled; 22 | bool minBtnEnabled; 23 | bool closeBtnEnabled; 24 | 25 | quint64 widgetWidth; 26 | 27 | QRect minRect; 28 | QRect maxRect; 29 | QRect clsRect; 30 | 31 | protected: 32 | void mousePressEvent( QMouseEvent * ); 33 | void mouseMoveEvent( QMouseEvent * ); 34 | void paintEvent( QPaintEvent * ); 35 | 36 | Q_SIGNALS: 37 | void maximizeWindow(); 38 | void minimizeWindow(); 39 | void closeWindow(); 40 | }; 41 | -------------------------------------------------------------------------------- /example/Gui/Widgets/RecentFiles/RecentFilesWidget.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * RecentFiles.hpp - MiniPDF's RecentFiles Header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | #include "Tools.hpp" 11 | #include "GuiWidgets.hpp" 12 | 13 | class RecentFile : public QPushButton{ 14 | Q_OBJECT 15 | 16 | public: 17 | RecentFile( QString ); 18 | QString file(); 19 | 20 | private: 21 | QIcon mIcon; 22 | 23 | QString mName; 24 | 25 | QString mDate; 26 | QString mSize; 27 | 28 | protected: 29 | void paintEvent( QPaintEvent * ); 30 | }; 31 | 32 | class RecentFiles : public QWidget { 33 | Q_OBJECT 34 | 35 | public : 36 | RecentFiles( QWidget *parent = 0 ); 37 | 38 | private: 39 | QStackedLayout *stackLyt; 40 | 41 | private slots: 42 | void openFiles(); 43 | void clearRecents(); 44 | 45 | Q_SIGNALS: 46 | void open(); 47 | void open( QString ); 48 | }; 49 | -------------------------------------------------------------------------------- /lib/Global.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project (https://gitlab.com/desq/) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include 33 | #include 34 | #include 35 | -------------------------------------------------------------------------------- /example/Gui/UI/MiniPdf.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * MiniPdf.hpp - MiniPdf Header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | 11 | #include 12 | #include 13 | 14 | #include "TabWidget.hpp" 15 | #include "GuiWidgets.hpp" 16 | #include "Settings.hpp" 17 | #include "MessageDialog.hpp" 18 | 19 | class MiniPdf : public QMainWindow { 20 | Q_OBJECT 21 | 22 | public : 23 | MiniPdf(); 24 | 25 | private : 26 | void setWindowProperties(); 27 | void setupGui(); 28 | 29 | void setupConnections(); 30 | void addToRecentList( QString ); 31 | 32 | TabWidget *Tabs; 33 | QStringList filesQueue; 34 | QStringList openedFiles; 35 | 36 | QPoint dragPosition; 37 | int recentIdx; 38 | 39 | private slots : 40 | void openFiles(); 41 | void openRecentFiles(); 42 | void loadFiles(); 43 | void reload(); 44 | 45 | void printFile(); 46 | 47 | void settings(); 48 | 49 | void closeTab(); 50 | void closeTab( int index ); 51 | void closeAllTabs(); 52 | 53 | void dfreeMode(); 54 | 55 | void messageReciever( const QString ); 56 | 57 | void toggleMaximizeRestore(); 58 | 59 | protected : 60 | void closeEvent( QCloseEvent * ); 61 | }; 62 | -------------------------------------------------------------------------------- /example/Gui/Widgets/FileDialog/FileDialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * FileDialog.hpp - MiniPDF's FileDialog class 4 | * 5 | */ 6 | 7 | #include "FileDialog.hpp" 8 | 9 | QStringList FileDialog::getOpenFileNames( QWidget *parent, QString location ) { 10 | 11 | QFileDialog dlg( parent, QString( "MiniPDF - Open Files" ), location, QString( "All Files (*);;PDF Files (*.pdf)" ) ); 12 | dlg.setWindowFlags( Qt::Dialog ); 13 | 14 | dlg.setAcceptMode( QFileDialog::AcceptOpen ); 15 | dlg.setFileMode( QFileDialog::ExistingFiles ); 16 | dlg.setFixedSize( 800, 600 ); 17 | dlg.setModal( true ); 18 | 19 | if ( dlg.exec() == QDialog::Accepted ) 20 | return dlg.selectedFiles(); 21 | 22 | else 23 | return QStringList(); 24 | }; 25 | 26 | QString FileDialog::getSaveFileName( QWidget *parent, QString location ) { 27 | 28 | QFileDialog dlg( parent, QString( "MiniPDF - Save File" ), location, QString( "All Files (*);;PDF Files (*.pdf)" ) ); 29 | dlg.setWindowFlags( Qt::Dialog ); 30 | 31 | dlg.setAcceptMode( QFileDialog::AcceptSave ); 32 | dlg.setFileMode( QFileDialog::AnyFile ); 33 | dlg.setFixedSize( 800, 600 ); 34 | dlg.setModal( true ); 35 | 36 | if ( dlg.exec() == QDialog::Accepted ) 37 | return dlg.selectedFiles().at( 0 ); 38 | 39 | else 40 | return QString(); 41 | }; 42 | -------------------------------------------------------------------------------- /example/Gui/Widgets/Misc/GuiWidgets.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * GuiWidgets.cpp - MiniPDF Gui Widgets Header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | 11 | class Separator : public QWidget { 12 | Q_OBJECT 13 | 14 | public: 15 | static QWidget* vertical( QWidget *parent = 0 ); 16 | static QWidget* horizontal( QWidget *parent = 0 ); 17 | 18 | private: 19 | enum Mode { 20 | Horizontal, 21 | Vertical 22 | }; 23 | 24 | Separator( Separator::Mode mode, QWidget *parent = 0 ); 25 | 26 | QLinearGradient vGrad, hGrad; 27 | Separator::Mode mMode; 28 | 29 | protected: 30 | void paintEvent( QPaintEvent * ); 31 | void resizeEvent( QResizeEvent * ); 32 | }; 33 | 34 | class Spacer { 35 | public: 36 | static QWidget *vertical( int space, QWidget *parent = 0 ); 37 | static QWidget* horizontal( int space, QWidget *parent = 0 ); 38 | }; 39 | 40 | class Stretch { 41 | 42 | public: 43 | static QWidget* vertical( QWidget *parent = 0 ); 44 | static QWidget* horizontal( QWidget *parent = 0 ); 45 | }; 46 | 47 | class LedLight : public QWidget { 48 | Q_OBJECT 49 | 50 | public: 51 | LedLight( quint64 radius, QWidget *parent = NULL ); 52 | 53 | bool isSafe(); 54 | void setSafe( bool ); 55 | 56 | public Q_SLOTS: 57 | void setModified( bool ); 58 | 59 | private: 60 | bool mSafe; 61 | quint64 mRadius; 62 | 63 | protected: 64 | void paintEvent( QPaintEvent * ); 65 | }; 66 | -------------------------------------------------------------------------------- /example/Gui/Dialogs/Dialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Dialog.cpp - NewBreeze Dialog Class 4 | * 5 | */ 6 | 7 | #include "Dialog.hpp" 8 | 9 | Dialog::Dialog( QWidget *parent ) : QDialog( parent ) { 10 | 11 | setupGUI(); 12 | setupDialogProperties(); 13 | }; 14 | 15 | void Dialog::setupGUI() { 16 | 17 | QAction *closeAct = new QAction( "&Close", this ); 18 | closeAct->setShortcut( QKeySequence( Qt::Key_Escape ) ); 19 | connect( closeAct, SIGNAL( triggered() ), this, SLOT( reject() ) ); 20 | addAction( closeAct ); 21 | }; 22 | 23 | void Dialog::setupDialogProperties() { 24 | 25 | /* Dialogs without close button */ 26 | setWindowFlags( Qt::CustomizeWindowHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint ); 27 | 28 | /* NewBreeze speciality */ 29 | setDialogIcon( QIcon( ":/icons/newbreeze.png" ) ); 30 | 31 | setWindowModality( Qt::ApplicationModal); 32 | 33 | /* Size and Size policy */ 34 | setMinimumSize( 500, 75 ); 35 | setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ) ); 36 | }; 37 | 38 | void Dialog::setLayout( QLayout *lyt ) { 39 | 40 | lyt->setContentsMargins( QMargins( 5, 5, 5, 5 ) ); 41 | QDialog::setLayout( lyt ); 42 | }; 43 | 44 | void Dialog::setDialogTitle( QString title ) { 45 | 46 | setWindowTitle( title ); 47 | }; 48 | 49 | void Dialog::setDialogIcon( QIcon icon ) { 50 | 51 | setWindowIcon( icon ); 52 | }; 53 | 54 | void Dialog::closeEvent( QCloseEvent *cEvent ) { 55 | 56 | QDialog::closeEvent( cEvent ); 57 | 58 | emit closed(); 59 | }; 60 | -------------------------------------------------------------------------------- /example/Resources/MiniPdf.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icons/arrow-down.png 4 | icons/arrow-left.png 5 | icons/arrow-right.png 6 | icons/arrow-up.png 7 | icons/checkbox_checked.png 8 | icons/checkbox_unchecked.png 9 | icons/clear.png 10 | icons/close.png 11 | icons/copy.png 12 | icons/cut.png 13 | icons/delete2.png 14 | icons/delete.png 15 | icons/error.png 16 | icons/exit-dfree.png 17 | icons/file.png 18 | icons/fonts.png 19 | icons/info.png 20 | icons/minipdf.png 21 | icons/new.png 22 | icons/ok.png 23 | icons/open.png 24 | icons/open-recent.png 25 | icons/paste.png 26 | icons/pdf.png 27 | icons/prefs.png 28 | icons/print.png 29 | icons/properties.png 30 | icons/question.png 31 | icons/quit.png 32 | icons/redo.png 33 | icons/replace.png 34 | icons/saveas.png 35 | icons/save.png 36 | icons/search.png 37 | icons/selectall.png 38 | icons/settings.png 39 | icons/stop.png 40 | icons/text.png 41 | icons/undo.png 42 | icons/warning.png 43 | icons/wrench.png 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/Document/RendererImpl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project (https://gitlab.com/desq/) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include "Renderer.hpp" 33 | #include "RenderOptions.hpp" 34 | 35 | namespace PdfWidget { 36 | class Page; 37 | } 38 | 39 | class RenderTask : public QObject, public QRunnable { 40 | Q_OBJECT; 41 | 42 | public: 43 | RenderTask( PdfWidget::Page *pg, QSize imgSz, PdfWidget::RenderOptions opts, qint64 id ); 44 | 45 | int pageNumber(); 46 | qint64 requestId(); 47 | QSize imageSize(); 48 | 49 | void invalidate(); 50 | 51 | void run(); 52 | 53 | private: 54 | PdfWidget::Page *mPage; 55 | QSize mImgSize; 56 | PdfWidget::RenderOptions mOpts; 57 | qint64 mId; 58 | 59 | Q_SIGNALS: 60 | void imageReady( int pageNo, QImage image, qint64 id ); 61 | }; 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PdfWidget 2 | ## A nascent PDF view written based on Qt 3 | 4 | ## This project is now archived. It is superseded by [QDocumentView](https://gitlab.com/marcusbritanicus/qdocumentview.git) project. QDV supports PDF and DjVu file formats as of today, and can easily be extended to support multiple file formats. Thank you all for your love and support. :slightly_smiling_face: 5 | 6 | Its very few features are 7 | - Two render backends: MuPdf and Poppler 8 | - Encryption support 9 | - Zoom in and Zoom out (10% to 400%) 10 | 11 | ### Qt4 and Qt5 builds are supported 12 | 13 | ### Notes for compiling - linux: 14 | 15 | * Download the sources 16 | - Git: `git clone https://gitlab.com/marcusbritanicus/PdfWidget PdfWidget-master` 17 | - Tar: `wget https://gitlab.com/marcusbritanicus/PdfWidget/archive/master.tar.gz && tar -xf master.tar.gz` 18 | * Enter `PdfWidget-master` 19 | * Open the terminal and type: `qmake && make` 20 | 21 | Because there are a lot of versions of mupdf out there and some of the older versions have now-outdated function names, 22 | mupdf source in included in the build tree. The MuPDF source is picked from Debian/Sid (Source Version 1.13.0+ds1-2). 23 | 24 | Because Noto, Droid and Hangul fonts bloat the library size to 45 MiB, I have removed them from the build tree. 25 | We also disable them using the flags `-DNOCJK -DTOFU`. To disable gl, we use `HAVE_GLUT=np` and use `-fPIC` so that 26 | we can link it with other shared objects. Though the source is nearly 11 MiB in size the library is ~8 MiB 27 | and the libpdfwidget.so will be after linking to mupdf ~3 MiB which is a decent size. 28 | 29 | ### Known issues 30 | - In the example implementation, changing the zoom causes the document to scroll to page 1. 31 | - Changing the zoom in the example implementation causes my system to freeze up at times. 32 | -------------------------------------------------------------------------------- /example/Main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2014 Britanicus 4 | * 5 | 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 24 | * MA 02110-1301, USA. 25 | * 26 | */ 27 | 28 | #include "MiniPdf.hpp" 29 | #include "MPApplication.hpp" 30 | 31 | int main( int argc, char **argv ) { 32 | 33 | /* Initialize the single application instance */ 34 | MPApplication app( argc, argv ); 35 | 36 | app.setOrganizationName( "MiniPdf" ); 37 | app.setApplicationName( "MiniPdf" ); 38 | 39 | /* We have no command line args */ 40 | if ( argc == 1 ) { 41 | if ( app.sendMessage( QString() ) ) 42 | return 0; 43 | } 44 | 45 | /* If we have command line args, we re-route them to the original instance */ 46 | else if ( argc >= 1 ) { 47 | 48 | QStringList files = app.arguments(); 49 | files.removeFirst(); 50 | if ( app.sendMessage( files.join( ";;" ) ) ) 51 | return 0; 52 | } 53 | 54 | MiniPdf *Gui = new MiniPdf(); 55 | Gui->showMaximized(); 56 | 57 | QObject::connect( &app, SIGNAL( messageReceived( const QString ) ), Gui, SLOT( messageReciever( const QString ) ) ); 58 | app.setActivationWindow( Gui, true ); 59 | 60 | return app.exec(); 61 | }; 62 | -------------------------------------------------------------------------------- /example/Gui/Widgets/Settings/Settings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * wSettings.cpp - MiniPDF's Settings Class 4 | * 5 | */ 6 | 7 | #include "Global.hpp" 8 | #include "Settings.hpp" 9 | 10 | wSettings::wSettings( QWidget *parent ) : QDialog( parent ) { 11 | 12 | setupGUI(); 13 | setWindowProperties(); 14 | } 15 | 16 | void wSettings::setFont( const QFont &nFont ) { 17 | 18 | QDialog::setFont( nFont ); 19 | fontBtn->setText( tr( "%1, %2" ).arg( nFont.family() ).arg( nFont.pointSize() ) ); 20 | } 21 | 22 | void wSettings::setupGUI() { 23 | 24 | QFont dFont = settings.value( "Font" ).value(); 25 | 26 | fontLbl = new QLabel( "Font: " ); 27 | fontBtn = new QPushButton( tr( "%1, %2" ).arg( dFont.family() ).arg( dFont.pointSize() ) ); 28 | fontBtn->setMinimumWidth( 200 ); 29 | 30 | QPushButton *closeBtn = new QPushButton(); 31 | closeBtn->setText( "&Close" ); 32 | closeBtn->setIcon( QIcon::fromTheme( "dialog-close" ) ); 33 | 34 | QVBoxLayout *baseLyt = new QVBoxLayout(); 35 | QHBoxLayout *fontLyt = new QHBoxLayout(); 36 | QHBoxLayout *cbtnLyt = new QHBoxLayout(); 37 | 38 | fontLyt->addWidget( fontLbl ); 39 | fontLyt->addWidget( fontBtn ); 40 | 41 | cbtnLyt->addStretch( 0 ); 42 | cbtnLyt->addWidget( closeBtn ); 43 | 44 | baseLyt->addLayout( fontLyt ); 45 | baseLyt->addLayout( cbtnLyt ); 46 | 47 | setLayout( baseLyt ); 48 | 49 | connect( fontBtn, SIGNAL( clicked() ), this, SLOT( chooseFont() ) ); 50 | connect( closeBtn, SIGNAL( clicked() ), this, SLOT( close() ) ); 51 | }; 52 | 53 | void wSettings::setWindowProperties() { 54 | 55 | setWindowTitle( "MiniPDF - Settings" ); 56 | setMinimumWidth( 250 ); 57 | }; 58 | 59 | void wSettings::chooseFont() { 60 | 61 | bool ok = false; 62 | QFont newFont = QFontDialog::getFont( &ok, settings.value( "Font" ).value(), this ); 63 | 64 | if ( ok ) { 65 | fontBtn->setText( tr( "%1, %2" ).arg( newFont.family() ).arg( newFont.pointSize() ) ); 66 | 67 | settings.setValue( "Font", QVariant( newFont ) ); 68 | settings.sync(); 69 | 70 | emit fontSet(); 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /example/Gui/Widgets/Buttons/ButtonSet.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ButtonSet.hpp - The Segmented Buttons Class Header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | #include "GuiWidgets.hpp" 11 | 12 | class ButtonSet : public QWidget { 13 | Q_OBJECT 14 | 15 | public: 16 | ButtonSet(); 17 | ButtonSet( QList ); 18 | ButtonSet( QStringList ); 19 | ButtonSet( QStringList, QList ); 20 | 21 | QList buttons(); 22 | 23 | QPushButton* segment( int ); 24 | 25 | void setSegmentIcon( int, QIcon ); 26 | void setSegmentText( int, QString ); 27 | 28 | void setSegmentWidth( int ); 29 | void setSegmentHeight( int ); 30 | 31 | void setSegmentShortcut( int, QKeySequence ); 32 | 33 | void setSegmentDisabled( int ); 34 | void setSegmentEnabled( int ); 35 | 36 | void insertSegment( QPushButton *button, int logicalPos ); 37 | void addSegment( QPushButton *button ); 38 | 39 | private: 40 | QHBoxLayout *btnsLyt; 41 | QList segments; 42 | 43 | int myButtonHeight; 44 | int myButtonWidth; 45 | 46 | private slots: 47 | void handleSegmentClick(); 48 | 49 | Q_SIGNALS: 50 | void segmentClicked( int ); 51 | }; 52 | 53 | class ButtonSet2 : public QWidget { 54 | Q_OBJECT 55 | 56 | public: 57 | ButtonSet2(); 58 | ButtonSet2( QList ); 59 | 60 | QList buttons(); 61 | 62 | QToolButton* segment( int ); 63 | 64 | void setSegmentIcon( int, QIcon ); 65 | 66 | void setSegmentWidth( int ); 67 | void setSegmentHeight( int ); 68 | 69 | void setSegmentShortcut( int, QKeySequence ); 70 | 71 | void setSegmentDisabled( int ); 72 | void setSegmentEnabled( int ); 73 | 74 | void insertSegment( QToolButton *button, int logicalPos ); 75 | void addSegment( QToolButton *button ); 76 | 77 | private: 78 | QHBoxLayout *btnsLyt; 79 | QList segments; 80 | 81 | int myButtonHeight; 82 | int myButtonWidth; 83 | 84 | private slots: 85 | void handleSegmentClick(); 86 | 87 | Q_SIGNALS: 88 | void segmentClicked( int ); 89 | }; 90 | -------------------------------------------------------------------------------- /lib/Document/Renderer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project (https://gitlab.com/desq/) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include "Global.hpp" 33 | #include "RenderOptions.hpp" 34 | 35 | class RenderTask; 36 | 37 | namespace PdfWidget { 38 | class Document; 39 | 40 | class Renderer: public QObject { 41 | Q_OBJECT; 42 | 43 | public: 44 | Renderer( QObject *parent = nullptr ); 45 | 46 | void setDocument( Document * ); 47 | QImage requestPage( int pg, QSize imgSz, RenderOptions opts ); 48 | 49 | void reload(); 50 | 51 | private: 52 | Document *mDoc; 53 | qint64 validFrom = -1; 54 | 55 | void validateImage( int pg, QImage img, qint64 id ); 56 | 57 | QHash pageCache; 58 | QVector pages; 59 | int pageCacheLimit = 20; 60 | 61 | QHash requestCache; 62 | QVector requests; 63 | int requestLimit = 5; 64 | 65 | QHash queuedRequests; 66 | QVector queue; 67 | 68 | Q_SIGNALS: 69 | void pageRendered( int ); 70 | }; 71 | }; 72 | -------------------------------------------------------------------------------- /example/Core/Tools/Tools.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * WTools.cpp - Some tools for MiniPDF 4 | * 5 | */ 6 | 7 | #include "Global.hpp" 8 | #include "Tools.hpp" 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | QString dirName( QString path ) { 17 | 18 | if ( path.endsWith( "/" ) ) 19 | path.chop( 1 ); 20 | 21 | char *dupPath = strdup( qPrintable( path ) ); 22 | QString dirPth = QString( dirname( dupPath ) ) + "/"; 23 | free( dupPath ); 24 | 25 | return dirPth; 26 | }; 27 | 28 | QString baseName( QString path ) { 29 | 30 | if ( path.endsWith( "/" ) ) 31 | path.chop( 1 ); 32 | 33 | char *dupPath = strdup( qPrintable( path ) ); 34 | QString basePth = QString( basename( dupPath ) ); 35 | free( dupPath ); 36 | 37 | return basePth; 38 | }; 39 | 40 | QString getMimeType( QString ) { 41 | 42 | return "application/pdf"; 43 | }; 44 | 45 | QPixmap getPixmap( QString path ) { 46 | 47 | QString mimeIconName = mimeDb.mimeTypeForFile( path ).iconName(); 48 | QString genericMimeIconName = mimeDb.mimeTypeForFile( path ).genericIconName(); 49 | 50 | QIcon icon = QIcon::fromTheme( "application-pdf", QIcon( ":/icons/pdf.png" ) ); 51 | 52 | return icon.pixmap( 48, 48 ); 53 | }; 54 | 55 | qint64 getSize( QString path ) { 56 | 57 | QFileInfo info( path ); 58 | return info.size(); 59 | }; 60 | 61 | mode_t getMode( QString path ) { 62 | 63 | struct stat fileAtts; 64 | if ( stat( path.toStdString().c_str(), &fileAtts ) != 0 ) { 65 | return -1; 66 | } 67 | 68 | return fileAtts.st_mode; 69 | }; 70 | 71 | QString formatSize( qint64 num ) { 72 | 73 | QString total; 74 | const qint64 kb = 1024; 75 | const qint64 mb = 1024 * kb; 76 | const qint64 gb = 1024 * mb; 77 | const qint64 tb = 1024 * gb; 78 | 79 | if ( num >= tb ) total = QString( "%1 TiB" ).arg( QString::number( qreal( num ) / tb, 'f', 3 ) ); 80 | else if ( num >= gb ) total = QString( "%1 GiB" ).arg( QString::number( qreal( num ) / gb, 'f', 2 ) ); 81 | else if ( num >= mb ) total = QString( "%1 MiB" ).arg( QString::number( qreal( num ) / mb, 'f', 1 ) ); 82 | else if ( num >= kb ) total = QString( "%1 KiB" ).arg( QString::number( qreal( num ) / kb,'f',1 ) ); 83 | else total = QString( "%1 bytes" ).arg( num ); 84 | 85 | return total; 86 | }; 87 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project( pdfwidget ) 2 | cmake_minimum_required( VERSION 3.16 ) 3 | 4 | set( PROJECT_VERSION 0.0.3 ) 5 | set( PROJECT_VERSION_MAJOR 0 ) 6 | set( PROJECT_VERSION_MINOR 0 ) 7 | set( PROJECT_VERSION_PATCH 3 ) 8 | 9 | set( PROJECT_VERSION_MAJOR_MINOR ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} ) 10 | add_compile_definitions(VERSION_TEXT="${PROJECT_VERSION}") 11 | 12 | set( CMAKE_CXX_STANDARD 17 ) 13 | set( CMAKE_INCLUDE_CURRENT_DIR ON ) 14 | set( CMAKE_BUILD_TYPE Release ) 15 | 16 | add_definitions ( -Wall ) 17 | if ( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT ) 18 | set( CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Location for installing the project" FORCE ) 19 | endif() 20 | 21 | set( CMAKE_AUTOMOC ON ) 22 | set( CMAKE_AUTORCC ON ) 23 | set( CMAKE_AUTOUIC ON ) 24 | 25 | find_package ( Qt5Widgets REQUIRED ) 26 | find_package ( Qt5Core REQUIRED ) 27 | find_package ( Qt5Gui REQUIRED ) 28 | find_package ( Qt5PrintSupport REQUIRED ) 29 | 30 | include_directories( 31 | Document 32 | MuPdf 33 | Poppler 34 | View 35 | ) 36 | 37 | set ( SOURCES 38 | Document/Document.cpp 39 | Document/Navigation.cpp 40 | Document/Renderer.cpp 41 | MuPdf/MuPdfDocument.cpp 42 | MuPdf/MuPdfDocument.hpp 43 | Poppler/PopplerDocument.cpp 44 | Poppler/PopplerDocument.hpp 45 | View/View.cpp 46 | View/ViewImpl.hpp 47 | View/ViewWidgets.cpp 48 | Document/RendererImpl.hpp 49 | ) 50 | 51 | set ( HEADERS 52 | Document/Document.hpp 53 | Document/Navigation.hpp 54 | Document/RenderOptions.hpp 55 | Document/Renderer.hpp 56 | View/View.hpp 57 | View/ViewWidgets.hpp 58 | ) 59 | 60 | add_library( pdfwidget SHARED ${SOURCES} ${HEADERS} ) 61 | set_target_properties( pdfwidget PROPERTIES VERSION ${PROJECT_VERSION} ) 62 | set_target_properties( pdfwidget PROPERTIES SOVERSION ${PROJECT_VERSION} ) 63 | set_target_properties( pdfwidget PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR_MINOR} ) 64 | set_target_properties( pdfwidget PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} ) 65 | target_link_libraries( 66 | pdfwidget 67 | Qt5::Core Qt5::Gui Qt5::Widgets Qt5::GuiPrivate Qt5::WidgetsPrivate 68 | poppler-qt5 69 | mupdf freetype z harfbuzz jpeg openjp2 jbig2dec mujs desq-core 70 | ) 71 | 72 | install( TARGETS pdfwidget EXPORT LIBRARY ) 73 | install( FILES ${HEADERS} DESTINATION include/pdfwidget/ ) 74 | -------------------------------------------------------------------------------- /example/Gui/Dialogs/MessageDialog.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * MessageDialog.hpp - MessageDialog.cpp header 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Global.hpp" 10 | #include "Dialog.hpp" 11 | #include "GuiWidgets.hpp" 12 | #include "ButtonSet.hpp" 13 | 14 | class MessageDialog : public Dialog { 15 | Q_OBJECT 16 | 17 | public: 18 | enum StandardButton { 19 | Ok = 0x00000400, 20 | Yes = 0x00004000, 21 | YesToAll = 0x00008000, 22 | No = 0x00010000, 23 | NoToAll = 0x00020000, 24 | Abort = 0x00040000, 25 | Retry = 0x00080000, 26 | Ignore = 0x00100000, 27 | Cancel = 0x00400000, 28 | Save = 0x00000800, 29 | Discard = 0x00800000, 30 | }; 31 | 32 | MessageDialog( QWidget*, QString icon = "", QString title = "", QString text = "", 33 | QList btns = QList() << MessageDialog::Ok, QWidget *info = 0 ); 34 | void setIcon( QString ); 35 | void setTitle( QString ); 36 | void setText( QString ); 37 | void setButtons( QStringList ); 38 | 39 | static void aboutNewBreeze(); 40 | static void aboutQt(); 41 | static int information( QWidget*, QString, QString, QList btns = QList() << MessageDialog::Ok, QWidget *infoWidget = 0 ); 42 | static int question( QWidget*, QString, QString, QList btns = QList() << MessageDialog::Ok, QWidget *infoWidget = 0 ); 43 | static int warning( QWidget*, QString, QString, QList btns = QList() << MessageDialog::Ok, QWidget *infoWidget = 0 ); 44 | static int error( QWidget*, QString, QString, QList btns = QList() << MessageDialog::Ok, QWidget *infoWidget = 0 ); 45 | static int critical( QWidget*, QString, QString, QList btns = QList() << MessageDialog::Ok, QWidget *infoWidget = 0 ); 46 | 47 | int retValue; 48 | 49 | private: 50 | QLabel *iconLbl, *textLbl; 51 | QPushButton *detailsBtn; 52 | QWidget *infoWidget; 53 | 54 | QByteArray origGeometry; 55 | 56 | protected: 57 | void keyPressEvent( QKeyEvent *keyEvent ); 58 | 59 | public slots: 60 | void close(); 61 | 62 | private slots: 63 | void toggleInfoWidget(); 64 | void buttonClickHandler(); 65 | 66 | signals: 67 | void closed(); 68 | }; 69 | -------------------------------------------------------------------------------- /example/Gui/Application/qtlockedfile.hpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 4 | ** All rights reserved. 5 | ** 6 | ** Contact: Nokia Corporation (qt-info@nokia.com) 7 | ** 8 | ** This file is part of a Qt Solutions component. 9 | ** 10 | ** You may use this file under the terms of the BSD license as follows: 11 | ** 12 | ** "Redistribution and use in source and binary forms, with or without 13 | ** modification, are permitted provided that the following conditions are 14 | ** met: 15 | ** * Redistributions of source code must retain the above copyright 16 | ** notice, this list of conditions and the following disclaimer. 17 | ** * Redistributions in binary form must reproduce the above copyright 18 | ** notice, this list of conditions and the following disclaimer in 19 | ** the documentation and/or other materials provided with the 20 | ** distribution. 21 | ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 22 | ** the names of its contributors may be used to endorse or promote 23 | ** products derived from this software without specific prior written 24 | ** permission. 25 | ** 26 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 37 | ** 38 | ****************************************************************************/ 39 | 40 | #ifndef QTLOCKEDFILE_H 41 | #define QTLOCKEDFILE_H 42 | 43 | #include 44 | 45 | class QtLockedFile : public QFile { 46 | 47 | public: 48 | enum LockMode { NoLock = 0, ReadLock, WriteLock }; 49 | 50 | QtLockedFile(); 51 | QtLockedFile(const QString &name); 52 | ~QtLockedFile(); 53 | 54 | bool open(OpenMode mode); 55 | 56 | bool lock(LockMode mode, bool block = true); 57 | bool unlock(); 58 | bool isLocked() const; 59 | LockMode lockMode() const; 60 | 61 | private: 62 | LockMode m_lock_mode; 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /lib/Poppler/PopplerDocument.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is a part of PdfWidget. 4 | * PdfWidget is the default document viewer for the DesQ Suite 5 | * Copyright 2019-2021 Britanicus 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "Document.hpp" 37 | #include "RenderOptions.hpp" 38 | 39 | #include 40 | 41 | class PdfPage; 42 | 43 | class PopplerDocument : public PdfWidget::Document { 44 | Q_OBJECT; 45 | 46 | public: 47 | PopplerDocument( QString pdfPath ); 48 | 49 | /* Set a password */ 50 | void setPassword( QString password ); 51 | 52 | /* Pdf Info / Metadata */ 53 | QString title() const; 54 | QString author() const; 55 | QString creator() const; 56 | QString producer() const; 57 | QString created() const; 58 | 59 | public Q_SLOTS: 60 | void load(); 61 | void close(); 62 | 63 | private: 64 | /* Pointer to our actual poppler document */ 65 | Poppler::Document *mPdfDoc; 66 | }; 67 | 68 | class PdfPage : public PdfWidget::Page { 69 | 70 | public: 71 | PdfPage( Poppler::Page *pg, int ); 72 | 73 | /* Size of the page */ 74 | QSizeF pageSize( qreal zoom = 1.0 ) const; 75 | 76 | /* Thumbnail of the page */ 77 | QImage thumbnail() const; 78 | 79 | /* Render and return a page */ 80 | QImage render( QSize, PdfWidget::RenderOptions ) const; 81 | QImage render( qreal zoomFactor, PdfWidget::RenderOptions ) const; 82 | 83 | /* Page Text */ 84 | QString pageText() const; 85 | 86 | /* Text of a Selection rectangle */ 87 | QString text( QRectF ) const; 88 | 89 | /* Search for @query in @pageNo or all pages */ 90 | QList search( QString query, PdfWidget::RenderOptions ) const; 91 | 92 | private: 93 | Poppler::Page *m_page; 94 | }; 95 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project( minipdf ) 2 | cmake_minimum_required( VERSION 3.16 ) 3 | 4 | set( PROJECT_VERSION 1.0.0 ) 5 | set( PROJECT_VERSION_MAJOR 1 ) 6 | set( PROJECT_VERSION_MINOR 0 ) 7 | set( PROJECT_VERSION_PATCH 0 ) 8 | 9 | set( PROJECT_VERSION_MAJOR_MINOR ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} ) 10 | add_compile_definitions(VERSION_TEXT="${PROJECT_VERSION}") 11 | 12 | set( CMAKE_CXX_STANDARD 17 ) 13 | set( CMAKE_INCLUDE_CURRENT_DIR ON ) 14 | set( CMAKE_BUILD_TYPE Release ) 15 | 16 | add_definitions ( -Wall ) 17 | if ( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT ) 18 | set( CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Location for installing the project" FORCE ) 19 | endif() 20 | 21 | set( CMAKE_AUTOMOC ON ) 22 | set( CMAKE_AUTORCC ON ) 23 | set( CMAKE_AUTOUIC ON ) 24 | 25 | find_package( Qt5Core REQUIRED ) 26 | find_package( Qt5Gui REQUIRED ) 27 | find_package( Qt5Widgets REQUIRED ) 28 | find_package( Qt5Network REQUIRED ) 29 | find_package( Qt5PrintSupport REQUIRED ) 30 | 31 | include_directories( 32 | Core 33 | Core/Tools 34 | Gui 35 | Gui/Application 36 | Gui/Dialogs 37 | Gui/UI 38 | Gui/Widgets 39 | Gui/Widgets/Buttons 40 | Gui/Widgets/FileDialog 41 | Gui/Widgets/Misc 42 | Gui/Widgets/RecentFiles 43 | Gui/Widgets/Settings 44 | Gui/Widgets/TabWidget 45 | ) 46 | 47 | set( HEADERS 48 | Core/Tools/Tools.hpp 49 | Global.hpp 50 | Gui/Dialogs/Dialog.hpp 51 | Gui/Dialogs/MessageDialog.hpp 52 | Gui/Application/qtlocalpeer.hpp 53 | Gui/Application/qtlockedfile.hpp 54 | Gui/Application/MPApplication.hpp 55 | Gui/Widgets/Buttons/ActionButtons.hpp 56 | Gui/Widgets/Buttons/ButtonSet.hpp 57 | Gui/Widgets/FileDialog/FileDialog.hpp 58 | Gui/Widgets/Misc/GuiWidgets.hpp 59 | Gui/Widgets/RecentFiles/RecentFilesWidget.hpp 60 | Gui/Widgets/Settings/Settings.hpp 61 | Gui/Widgets/TabWidget/TabWidget.hpp 62 | Gui/UI/MiniPdf.hpp 63 | ) 64 | 65 | set( SOURCES 66 | Core/Tools/Tools.cpp 67 | Gui/Dialogs/Dialog.cpp 68 | Gui/Dialogs/MessageDialog.cpp 69 | Gui/Application/qtlocalpeer.cpp 70 | Gui/Application/MPApplication.cpp 71 | Gui/Widgets/Buttons/ButtonSet.cpp 72 | Gui/Widgets/Buttons/ActionButtons.cpp 73 | Gui/Widgets/FileDialog/FileDialog.cpp 74 | Gui/Widgets/Misc/GuiWidgets.cpp 75 | Gui/Widgets/RecentFiles/RecentFilesWidget.cpp 76 | Gui/Widgets/Settings/Settings.cpp 77 | Gui/Widgets/TabWidget/TabWidget.cpp 78 | Gui/UI/MiniPdf.cpp 79 | Main.cpp 80 | ) 81 | 82 | set ( RESOURCES 83 | Resources/MiniPdf.qrc 84 | ) 85 | 86 | add_executable( minipdf ${SOURCES} ${HEADERS} ${RESOURCES} ) 87 | target_link_libraries( 88 | minipdf 89 | Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network Qt5::PrintSupport 90 | pdfwidget 91 | ) 92 | 93 | install( TARGETS minipdf DESTINATION bin ) 94 | install( PROGRAMS minipdf.desktop DESTINATION share/applications ) 95 | install( FILES minipdf.svg DESTINATION share/icons/hicolor/scalable/apps/ ) 96 | -------------------------------------------------------------------------------- /example/Gui/Application/qtlocalpeer.hpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 4 | ** All rights reserved. 5 | ** 6 | ** Contact: Nokia Corporation (qt-info@nokia.com) 7 | ** 8 | ** This file is part of a Qt Solutions component. 9 | ** 10 | ** You may use this file under the terms of the BSD license as follows: 11 | ** 12 | ** "Redistribution and use in source and binary forms, with or without 13 | ** modification, are permitted provided that the following conditions are 14 | ** met: 15 | ** * Redistributions of source code must retain the above copyright 16 | ** notice, this list of conditions and the following disclaimer. 17 | ** * Redistributions in binary form must reproduce the above copyright 18 | ** notice, this list of conditions and the following disclaimer in 19 | ** the documentation and/or other materials provided with the 20 | ** distribution. 21 | ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 22 | ** the names of its contributors may be used to endorse or promote 23 | ** products derived from this software without specific prior written 24 | ** permission. 25 | ** 26 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 37 | ** 38 | ****************************************************************************/ 39 | 40 | #pragma once 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | 49 | class QtLocalPeer : public QObject { 50 | Q_OBJECT 51 | 52 | public: 53 | QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); 54 | bool isClient(); 55 | bool sendMessage(const QString &message, int timeout); 56 | QString applicationId() const 57 | { return id; } 58 | 59 | QString socketName(); 60 | 61 | void shutdown(); 62 | 63 | Q_SIGNALS: 64 | void messageReceived(const QString &message); 65 | 66 | protected Q_SLOTS: 67 | void receiveConnection(); 68 | 69 | protected: 70 | QString id; 71 | QString mSocketName; 72 | QLocalServer* server; 73 | QtLockedFile lockFile; 74 | 75 | private: 76 | static const char* ack; 77 | }; 78 | -------------------------------------------------------------------------------- /lib/MuPdf/MuPdfDocument.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is a part of PdfWidget. 4 | * PdfWidget is the default document viewer for the DesQ Suite 5 | * Copyright 2019-2021 Britanicus 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "Document.hpp" 37 | #include "RenderOptions.hpp" 38 | 39 | extern "C" { 40 | #include 41 | } 42 | 43 | class MuPage; 44 | 45 | class MuPdfDocument : public PdfWidget::Document { 46 | Q_OBJECT; 47 | 48 | public: 49 | MuPdfDocument( QString pdfPath ); 50 | 51 | /* Set a password */ 52 | void setPassword( QString password ); 53 | 54 | /* Pdf Info / Metadata */ 55 | QString title() const; 56 | QString author() const; 57 | QString creator() const; 58 | QString producer() const; 59 | QString created() const; 60 | 61 | public Q_SLOTS: 62 | void load(); 63 | void close(); 64 | 65 | private: 66 | /* Pointer to our actual mupdf document */ 67 | fz_context *mCtx; 68 | fz_document *mFzDoc; 69 | 70 | int mPageCount; 71 | 72 | Q_SIGNALS: 73 | void passwordChanged(); 74 | void passwordRequired(); 75 | void reloadDocument(); 76 | void statusChanged( Document::Status status ); 77 | void pageCountChanged( int pageCount ); 78 | }; 79 | 80 | class MuPage : public PdfWidget::Page { 81 | 82 | public: 83 | MuPage( fz_context *ctx, fz_page *pg, int ); 84 | ~MuPage(); 85 | 86 | /* Size of the page */ 87 | QSizeF pageSize( qreal zoom = 1.0 ) const; 88 | 89 | /* Thumbnail of the page */ 90 | QImage thumbnail() const; 91 | 92 | /* Render and return a page */ 93 | QImage render( QSize, PdfWidget::RenderOptions ) const; 94 | QImage render( qreal zoomFactor, PdfWidget::RenderOptions ) const; 95 | 96 | /* Page Text */ 97 | QString pageText() const; 98 | 99 | /* Text of a Selection rectangle */ 100 | QString text( QRectF ) const; 101 | 102 | /* Search for @query in @pageNo or all pages */ 103 | QList search( QString query, PdfWidget::RenderOptions ) const; 104 | 105 | private: 106 | fz_page *mPage; 107 | fz_context *mCtx; 108 | }; 109 | -------------------------------------------------------------------------------- /example/Gui/Application/MPApplication.hpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright ( C ) 2010 Nokia Corporation and/or its subsidiary( -ies ). 4 | ** All rights reserved. 5 | ** 6 | ** Contact: Nokia Corporation ( qt-info@nokia.com ) 7 | ** 8 | ** This file is part of a Qt Solutions component. 9 | ** 10 | ** You may use this file under the terms of the BSD license as follows: 11 | ** 12 | ** "Redistribution and use in source and binary forms, with or without 13 | ** modification, are permitted provided that the following conditions are 14 | ** met: 15 | ** * Redistributions of source code must retain the above copyright 16 | ** notice, this list of conditions and the following disclaimer. 17 | ** * Redistributions in binary form must reproduce the above copyright 18 | ** notice, this list of conditions and the following disclaimer in 19 | ** the documentation and/or other materials provided with the 20 | ** distribution. 21 | ** * Neither the name of Nokia Corporation and its Subsidiary( -ies ) nor 22 | ** the names of its contributors may be used to endorse or promote 23 | ** products derived from this software without specific prior written 24 | ** permission. 25 | ** 26 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT 32 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY 34 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | ** ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE 36 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 37 | ** 38 | ****************************************************************************/ 39 | 40 | #pragma once 41 | 42 | #include 43 | #include 44 | 45 | class QtLocalPeer; 46 | 47 | class MPApplication : public QApplication { 48 | Q_OBJECT 49 | 50 | public: 51 | MPApplication( int &argc, char **argv, bool GUIenabled = true ); 52 | MPApplication( const QString &id, int &argc, char **argv ); 53 | 54 | bool isRunning(); 55 | QString id() const; 56 | 57 | void setActivationWindow( QWidget* aw, bool activateOnMessage = true ); 58 | QWidget* activationWindow() const; 59 | 60 | // Obsolete: 61 | void initialize( bool dummy = true ) { 62 | isRunning(); 63 | Q_UNUSED( dummy ) 64 | } 65 | 66 | public Q_SLOTS: 67 | bool sendMessage( const QString &message, int timeout = 5000 ); 68 | void activateWindow(); 69 | void disconnect(); 70 | 71 | Q_SIGNALS: 72 | void messageReceived( const QString &message ); 73 | 74 | private: 75 | void sysInit( const QString &appId = QString() ); 76 | QtLocalPeer *peer; 77 | QWidget *actWin; 78 | }; 79 | -------------------------------------------------------------------------------- /lib/View/ViewImpl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is a part of DesQEye. 4 | * DesQEye is an Image Viewer for the DesQ Suite 5 | * Copyright 2019-2021 Britanicus 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include "View.hpp" 33 | 34 | #include 35 | #include 36 | 37 | namespace PdfWidget { 38 | class Renderer; 39 | class Document; 40 | 41 | class ViewPrivate : public QAbstractScrollAreaPrivate { 42 | 43 | Q_DECLARE_PUBLIC( PdfWidget::View ); 44 | 45 | public: 46 | ViewPrivate(); 47 | void init(); 48 | 49 | void documentStatusChanged(); 50 | void currentPageChanged( int currentPage ); 51 | void calculateViewport(); 52 | void setViewport( QRect viewport ); 53 | void updateScrollBars(); 54 | 55 | void invalidateDocumentLayout(); 56 | 57 | qreal yPositionForPage( int page ) const; 58 | 59 | qreal zoomFactor() const; 60 | 61 | struct DocumentLayout { 62 | QSize documentSize; 63 | QHash pageGeometries; 64 | }; 65 | 66 | DocumentLayout calculateDocumentLayout() const; 67 | void updateDocumentLayout(); 68 | 69 | QPointer m_document = nullptr; 70 | PdfWidget::Navigation* m_pageNavigation = nullptr; 71 | PdfWidget::Renderer *m_pageRenderer = nullptr; 72 | 73 | View::PageMode m_pageMode; 74 | View::ZoomMode m_zoomMode; 75 | qreal m_zoomFactor; 76 | PdfWidget::RenderOptions m_renderOpts; 77 | 78 | int m_pageSpacing; 79 | QMargins m_documentMargins; 80 | 81 | bool m_blockPageScrolling; 82 | 83 | QMetaObject::Connection m_documentStatusChangedConnection; 84 | QMetaObject::Connection m_reloadDocumentConnection; 85 | 86 | QRect m_viewport; 87 | 88 | DocumentLayout m_documentLayout; 89 | 90 | qreal m_screenResolution; // pixels per point 91 | bool pendingResize = false; 92 | }; 93 | } 94 | 95 | Q_DECLARE_TYPEINFO( PdfWidget::ViewPrivate::DocumentLayout, Q_MOVABLE_TYPE ); 96 | -------------------------------------------------------------------------------- /lib/Document/RenderOptions.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project ( https://gitlab.com/desq/ ) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include 33 | 34 | namespace PdfWidget { 35 | class RenderOptions { 36 | 37 | public: 38 | enum Rotation { 39 | Rotate0, 40 | Rotate90, 41 | Rotate180, 42 | Rotate270 43 | }; 44 | 45 | enum RenderFlag { 46 | NoRenderFlags = 0x000, 47 | RenderAnnotations = 0x001, 48 | RenderOptimizedForLcd = 0x002, 49 | RenderGrayscale = 0x004, 50 | RenderForceHalftone = 0x008, 51 | RenderTextAliased = 0x010, 52 | RenderImageAliased = 0x020, 53 | RenderPathAliased = 0x040 54 | }; 55 | Q_DECLARE_FLAGS( RenderFlags, RenderFlag ); 56 | 57 | RenderOptions() : data( 0 ) {}; 58 | 59 | Rotation rotation() const { 60 | return static_cast( bits.rotation ); 61 | }; 62 | 63 | void setRotation( Rotation _rotation ) { 64 | bits.rotation = _rotation; 65 | }; 66 | 67 | RenderFlags renderFlags() const { 68 | return static_cast( bits.renderFlags ); 69 | }; 70 | 71 | void setRenderFlags( RenderFlags _renderFlags ) { 72 | bits.renderFlags = _renderFlags; 73 | }; 74 | 75 | private: 76 | friend inline bool operator==( RenderOptions lhs, RenderOptions rhs ); 77 | 78 | struct Bits { 79 | quint32 renderFlags : 8; 80 | quint32 rotation : 3; 81 | quint32 reserved : 21; 82 | quint32 reserved2 : 32; 83 | }; 84 | 85 | union { 86 | Bits bits; 87 | quint64 data; 88 | }; 89 | }; 90 | 91 | inline bool operator==( RenderOptions lhs, RenderOptions rhs ) { 92 | 93 | return lhs.data == rhs.data; 94 | }; 95 | 96 | inline bool operator!=( RenderOptions lhs, RenderOptions rhs ) { 97 | 98 | return !operator==( lhs, rhs ); 99 | }; 100 | }; 101 | 102 | Q_DECLARE_METATYPE( PdfWidget::RenderOptions ); 103 | -------------------------------------------------------------------------------- /lib/Document/Navigation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project ( https://gitlab.com/desq/ ) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #include "Navigation.hpp" 31 | #include "Document.hpp" 32 | 33 | #include 34 | 35 | PdfWidget::Navigation::Navigation( QObject *parent ) : QObject( *new NavigationPrivate, parent ) { 36 | 37 | } 38 | 39 | PdfWidget::Navigation::~Navigation() { 40 | } 41 | 42 | PdfWidget::Document* PdfWidget::Navigation::document() const { 43 | 44 | Q_D( const PdfWidget::Navigation ); 45 | 46 | return d->m_document; 47 | }; 48 | 49 | void PdfWidget::Navigation::setDocument( Document *document ) { 50 | 51 | Q_D( PdfWidget::Navigation ); 52 | 53 | if ( d->m_document == document ) 54 | return; 55 | 56 | if ( d->m_document ) 57 | disconnect( d->m_documentStatusChangedConnection ); 58 | 59 | d->m_document = document; 60 | emit documentChanged( d->m_document ); 61 | 62 | if ( d->m_document ) 63 | d->m_documentStatusChangedConnection = connect( d->m_document.data(), &Document::statusChanged, this, [d](){ d->documentStatusChanged(); } ); 64 | 65 | d->update(); 66 | } 67 | 68 | int PdfWidget::Navigation::currentPage() const { 69 | 70 | Q_D( const PdfWidget::Navigation ); 71 | 72 | return d->m_currentPage; 73 | } 74 | 75 | void PdfWidget::Navigation::setCurrentPage( int newPage ) { 76 | 77 | Q_D( PdfWidget::Navigation ); 78 | 79 | if ( newPage < 0 || newPage >= d->m_pageCount ) 80 | return; 81 | 82 | if ( d->m_currentPage == newPage ) 83 | return; 84 | 85 | d->m_currentPage = newPage; 86 | emit currentPageChanged( d->m_currentPage ); 87 | 88 | d->updatePrevNext(); 89 | } 90 | 91 | int PdfWidget::Navigation::pageCount() const { 92 | 93 | Q_D( const PdfWidget::Navigation ); 94 | return d->m_pageCount; 95 | } 96 | 97 | bool PdfWidget::Navigation::canGoToPreviousPage() const { 98 | 99 | Q_D( const PdfWidget::Navigation ); 100 | return d->m_canGoToPreviousPage; 101 | } 102 | 103 | bool PdfWidget::Navigation::canGoToNextPage() const { 104 | 105 | Q_D( const PdfWidget::Navigation ); 106 | return d->m_canGoToNextPage; 107 | } 108 | 109 | void PdfWidget::Navigation::goToPreviousPage() { 110 | 111 | Q_D( PdfWidget::Navigation ); 112 | 113 | if ( d->m_currentPage > 0 ) 114 | setCurrentPage( d->m_currentPage - 1 ); 115 | } 116 | 117 | void PdfWidget::Navigation::goToNextPage() { 118 | 119 | Q_D( PdfWidget::Navigation ); 120 | 121 | if ( d->m_currentPage < d->m_pageCount - 1 ) 122 | setCurrentPage( d->m_currentPage + 1 ); 123 | } 124 | -------------------------------------------------------------------------------- /lib/View/ViewWidgets.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is a part of PdfWidget. 4 | * PdfWidget is the default document viewer for the DesQ Suite 5 | * Copyright 2019-2021 Britanicus 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include "Global.hpp" 33 | 34 | class Zoom : public QWidget { 35 | Q_OBJECT 36 | 37 | public: 38 | Zoom( QWidget *parent ); 39 | 40 | void setEnlargeEnabled( bool ); 41 | void setDwindleEnabled( bool ); 42 | 43 | private: 44 | typedef struct _state { 45 | bool mouseIn; 46 | bool inDwindle; 47 | bool inEnlarge; 48 | bool dwindlePressed; 49 | bool enlargePressed; 50 | } ZoomBtnState; 51 | 52 | bool isEnlargeEnabled; 53 | bool isDwindleEnabled; 54 | 55 | ZoomBtnState btnState; 56 | 57 | QRectF enlargeRect; 58 | QRectF dwindleRect; 59 | 60 | QPixmap enlargeIcon; 61 | QPixmap dwindleIcon; 62 | 63 | protected: 64 | void enterEvent( QEvent * ) override; 65 | void leaveEvent( QEvent * ) override; 66 | 67 | void mousePressEvent( QMouseEvent * ) override; 68 | void mouseMoveEvent( QMouseEvent * ) override; 69 | void mouseReleaseEvent( QMouseEvent * ) override; 70 | 71 | void paintEvent( QPaintEvent *pEvent ) override; 72 | 73 | Q_SIGNALS: 74 | void clicked( QString ); 75 | }; 76 | 77 | class PageWidget : public QWidget { 78 | Q_OBJECT 79 | 80 | public: 81 | PageWidget( QWidget *parent ); 82 | 83 | void setMaximumPages( int ); 84 | void setCurrentPage( int ); 85 | 86 | private: 87 | typedef struct _state { 88 | bool mouseIn; 89 | bool inPrevious; 90 | bool inNext; 91 | bool inText; 92 | bool previousPressed; 93 | bool nextPressed; 94 | bool textPressed; 95 | } ZoomBtnState; 96 | 97 | bool isNextEnabled; 98 | bool isPreviousEnabled; 99 | 100 | ZoomBtnState btnState; 101 | 102 | QRectF nextRect; 103 | QRectF previousRect; 104 | QRectF textRect; 105 | 106 | QPixmap nextIcon; 107 | QPixmap previousIcon; 108 | 109 | int maxPages = 0; 110 | int curPage = 0; 111 | 112 | protected: 113 | void enterEvent( QEvent * ) override; 114 | void leaveEvent( QEvent * ) override; 115 | 116 | void mousePressEvent( QMouseEvent * ) override; 117 | void mouseMoveEvent( QMouseEvent * ) override; 118 | void mouseReleaseEvent( QMouseEvent * ) override; 119 | 120 | void paintEvent( QPaintEvent *pEvent ) override; 121 | 122 | Q_SIGNALS: 123 | void loadPage( int ); 124 | }; 125 | -------------------------------------------------------------------------------- /example/Gui/Widgets/Buttons/ActionButtons.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ActionButtons.cpp - Minimize/Maximize/Close Button Widget Class 4 | * 5 | */ 6 | 7 | #include "ActionButtons.hpp" 8 | 9 | ActionButtons::ActionButtons( bool minBtn, bool maxBtn, bool closeBtn ) : QWidget() { 10 | 11 | minRect = QRect( 0, 0, 0, 0 ); 12 | maxRect = QRect( 0, 0, 0, 0 ); 13 | clsRect = QRect( 0, 0, 0, 0 ); 14 | 15 | painter = new QPainter(); 16 | 17 | minBtnEnabled = minBtn; 18 | maxBtnEnabled = maxBtn; 19 | closeBtnEnabled = closeBtn; 20 | 21 | widgetWidth = 0; 22 | int startx = 5; 23 | 24 | if ( minBtn ) { 25 | widgetWidth += 16 + 5; 26 | minRect = QRect( startx, 2, 16, 16 ); 27 | startx += 16 + 5; 28 | } 29 | 30 | if ( maxBtn ) { 31 | widgetWidth += 16 + 5; 32 | maxRect = QRect( startx, 2, 16, 16 ); 33 | startx += 16 + 5; 34 | } 35 | 36 | if ( closeBtn ) { 37 | widgetWidth += 16 + 5; 38 | clsRect = QRect( startx, 2, 16, 16 ); 39 | } 40 | 41 | if ( widgetWidth ) 42 | widgetWidth += 5; 43 | 44 | setFixedSize( widgetWidth, 20 ); 45 | 46 | setMouseTracking( true ); 47 | }; 48 | 49 | ActionButtons::~ActionButtons() { 50 | 51 | if ( painter->isActive() ) 52 | painter->end(); 53 | 54 | delete painter; 55 | }; 56 | 57 | void ActionButtons::mousePressEvent( QMouseEvent *mEvent ) { 58 | 59 | if ( mEvent->button() == Qt::LeftButton ) { 60 | if ( minRect.contains( mEvent->pos() ) ) 61 | emit minimizeWindow(); 62 | 63 | else if ( maxRect.contains( mEvent->pos() ) ) 64 | emit maximizeWindow(); 65 | 66 | else if ( clsRect.contains( mEvent->pos() ) ) 67 | emit closeWindow(); 68 | 69 | else 70 | QWidget::mousePressEvent( mEvent ); 71 | } 72 | 73 | else { 74 | QWidget::mousePressEvent( mEvent ); 75 | } 76 | 77 | mEvent->accept(); 78 | }; 79 | 80 | void ActionButtons::mouseMoveEvent( QMouseEvent *mEvent ) { 81 | 82 | repaint(); 83 | mEvent->accept(); 84 | }; 85 | 86 | void ActionButtons::paintEvent( QPaintEvent *pEvent ) { 87 | 88 | if ( not widgetWidth ) { 89 | pEvent->ignore(); 90 | return; 91 | } 92 | 93 | painter->begin( this ); 94 | painter->setRenderHints( QPainter::Antialiasing ); 95 | painter->setPen( Qt::NoPen ); 96 | 97 | QPoint mousePos = mapFromGlobal( QCursor::pos() ); 98 | 99 | int startx = 5; 100 | if ( minBtnEnabled ) { 101 | if ( minRect.contains( mousePos ) ) { 102 | painter->setBrush( QBrush( QColor( 0, 100, 0, 180 ) ) ); 103 | painter->drawRoundedRect( startx -1, 1, 18, 18, 3, 3 ); 104 | painter->setBrush( Qt::NoBrush ); 105 | } 106 | QPixmap minIcon = QIcon( ":/icons/arrow-down.png" ).pixmap( 16, 16 ); 107 | painter->drawPixmap( startx, 2, 16, 16, minIcon ); 108 | startx += 16 + 5; 109 | } 110 | 111 | if ( maxBtnEnabled ) { 112 | if ( maxRect.contains( mousePos ) ) { 113 | painter->setBrush( QBrush( QColor( 0, 0, 100, 180 ) ) ); 114 | painter->drawRoundedRect( startx -1, 1, 18, 18, 3, 3 ); 115 | painter->setBrush( Qt::NoBrush ); 116 | } 117 | QPixmap maxIcon = QIcon( ":/icons/arrow-up.png" ).pixmap( 16, 16 ); 118 | painter->drawPixmap( startx, 2, 16, 16, maxIcon ); 119 | startx += 16 + 5; 120 | } 121 | 122 | if ( closeBtnEnabled ) { 123 | if ( clsRect.contains( mousePos ) ) { 124 | painter->setBrush( QBrush( QColor( 100, 0, 0, 180 ) ) ); 125 | painter->drawRoundedRect( startx -1, 1, 18, 18, 3, 3 ); 126 | painter->setBrush( Qt::NoBrush ); 127 | } 128 | QPixmap closeIcon = QIcon( ":/icons/delete2.png" ).pixmap( 16, 16 ); 129 | painter->drawPixmap( startx, 2, 16, 16, closeIcon ); 130 | } 131 | 132 | painter->end(); 133 | pEvent->accept(); 134 | }; 135 | -------------------------------------------------------------------------------- /example/Gui/Widgets/TabWidget/TabWidget.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * * TabWidget.cpp - MiniPDF's TabWidget 4 | * 5 | */ 6 | 7 | #include "TabWidget.hpp" 8 | 9 | TabWidget::TabWidget( QWidget *parent ) : QTabWidget( parent ) { 10 | 11 | // TabBar settings 12 | setMovable( true ); 13 | setDocumentMode( true ); 14 | setTabsClosable( true ); 15 | 16 | setElideMode( Qt::ElideMiddle ); 17 | 18 | QToolButton *openBtn = new QToolButton( this ); 19 | openBtn->setIcon( QIcon( ":/icons/open.png" ) ); 20 | openBtn->setShortcut( tr( "Ctrl+O" ) ); 21 | connect( openBtn, SIGNAL( clicked() ), this, SIGNAL( open() ) ); 22 | 23 | setCornerWidget( openBtn, Qt::TopLeftCorner ); 24 | 25 | QAction *nextTabAct = new QAction( "Next Tab", this ); 26 | nextTabAct->setShortcuts( QList() << QKeySequence( "Ctrl+Tab" ) << QKeySequence( "Ctrl+PgDown" ) ); 27 | connect( nextTabAct, SIGNAL( triggered() ), this, SLOT( nextTab() ) ); 28 | addAction( nextTabAct ); 29 | 30 | QAction *prevTabAct = new QAction( "Previous Tab", this ); 31 | prevTabAct->setShortcuts( QList() << QKeySequence( "Ctrl+Shift+Tab" ) << QKeySequence( "Ctrl+PgUp" ) ); 32 | connect( prevTabAct, SIGNAL( triggered() ), this, SLOT( prevTab() ) ); 33 | addAction( prevTabAct ); 34 | 35 | QAction *moveTabRightAct = new QAction( "Move Tab to Right", this ); 36 | moveTabRightAct->setShortcuts( QList() << QKeySequence( "Alt+PgDown" ) ); 37 | connect( moveTabRightAct, SIGNAL( triggered() ), this, SLOT( moveTabRight() ) ); 38 | addAction( moveTabRightAct ); 39 | 40 | QAction *moveTabLeftAct = new QAction( "Previous Tab", this ); 41 | moveTabLeftAct->setShortcuts( QList() << QKeySequence( "Alt+PgUp" ) ); 42 | connect( moveTabLeftAct, SIGNAL( triggered() ), this, SLOT( moveTabLeft() ) ); 43 | addAction( moveTabLeftAct ); 44 | 45 | QAction *moveTabLastAct = new QAction( "Move Tab to Last", this ); 46 | moveTabLastAct->setShortcuts( QList() << QKeySequence( "Alt+Shift+PgDown" ) ); 47 | connect( moveTabLastAct, SIGNAL( triggered() ), this, SLOT( moveTabLast() ) ); 48 | addAction( moveTabLastAct ); 49 | 50 | QAction *moveTabFirstAct = new QAction( "Move Tab to First", this ); 51 | moveTabFirstAct->setShortcuts( QList() << QKeySequence( "Alt+Shift+PgUp" ) ); 52 | connect( moveTabFirstAct, SIGNAL( triggered() ), this, SLOT( moveTabFirst() ) ); 53 | addAction( moveTabFirstAct ); 54 | }; 55 | 56 | void TabWidget::removeTab( int index ) { 57 | /* Does the tab get automatically get removed if we delete the widget? */ 58 | 59 | widget( index )->deleteLater(); 60 | QTabWidget::removeTab( index ); 61 | }; 62 | 63 | void TabWidget::setTabTextColor( int index, QColor color ) { 64 | 65 | tabBar()->setTabTextColor( index, color ); 66 | tabBar()->update(); 67 | }; 68 | 69 | void TabWidget::nextTab() { 70 | 71 | if ( currentIndex() + 1 == count() ) 72 | setCurrentIndex( 0 ); 73 | 74 | else 75 | setCurrentIndex( currentIndex() + 1 ); 76 | }; 77 | 78 | void TabWidget::prevTab() { 79 | 80 | if ( currentIndex() - 1 < 0 ) 81 | setCurrentIndex( count() - 1 ); 82 | 83 | else 84 | setCurrentIndex( currentIndex() - 1 ); 85 | }; 86 | 87 | void TabWidget::moveTabRight() { 88 | 89 | if ( currentIndex() + 1 == count() ) 90 | return; 91 | 92 | else 93 | tabBar()->moveTab( currentIndex(), currentIndex() + 1 ); 94 | }; 95 | 96 | void TabWidget::moveTabLeft() { 97 | 98 | if ( currentIndex() == 0 ) 99 | return; 100 | 101 | else 102 | tabBar()->moveTab( currentIndex(), currentIndex() - 1 ); 103 | }; 104 | 105 | void TabWidget::moveTabFirst() { 106 | 107 | tabBar()->moveTab( currentIndex(), 0 ); 108 | }; 109 | 110 | void TabWidget::moveTabLast() { 111 | 112 | tabBar()->moveTab( currentIndex(), count() - 1 ); 113 | }; 114 | -------------------------------------------------------------------------------- /example/Gui/Application/qtlockedfile_unix.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 4 | ** All rights reserved. 5 | ** 6 | ** Contact: Nokia Corporation (qt-info@nokia.com) 7 | ** 8 | ** This file is part of a Qt Solutions component. 9 | ** 10 | ** You may use this file under the terms of the BSD license as follows: 11 | ** 12 | ** "Redistribution and use in source and binary forms, with or without 13 | ** modification, are permitted provided that the following conditions are 14 | ** met: 15 | ** * Redistributions of source code must retain the above copyright 16 | ** notice, this list of conditions and the following disclaimer. 17 | ** * Redistributions in binary form must reproduce the above copyright 18 | ** notice, this list of conditions and the following disclaimer in 19 | ** the documentation and/or other materials provided with the 20 | ** distribution. 21 | ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 22 | ** the names of its contributors may be used to endorse or promote 23 | ** products derived from this software without specific prior written 24 | ** permission. 25 | ** 26 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 37 | ** 38 | ****************************************************************************/ 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include 46 | 47 | bool QtLockedFile::lock(LockMode mode, bool block) { 48 | if (!isOpen()) { 49 | qWarning("QtLockedFile::lock(): file is not opened"); 50 | return false; 51 | } 52 | 53 | if (mode == NoLock) 54 | return unlock(); 55 | 56 | if (mode == m_lock_mode) 57 | return true; 58 | 59 | if (m_lock_mode != NoLock) 60 | unlock(); 61 | 62 | struct flock fl; 63 | fl.l_whence = SEEK_SET; 64 | fl.l_start = 0; 65 | fl.l_len = 0; 66 | fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; 67 | int cmd = block ? F_SETLKW : F_SETLK; 68 | int ret = fcntl(handle(), cmd, &fl); 69 | 70 | if (ret == -1) { 71 | if (errno != EINTR && errno != EAGAIN) 72 | qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); 73 | return false; 74 | } 75 | 76 | 77 | m_lock_mode = mode; 78 | return true; 79 | } 80 | 81 | 82 | bool QtLockedFile::unlock() { 83 | if (!isOpen()) { 84 | qWarning("QtLockedFile::unlock(): file is not opened"); 85 | return false; 86 | } 87 | 88 | if (!isLocked()) 89 | return true; 90 | 91 | struct flock fl; 92 | fl.l_whence = SEEK_SET; 93 | fl.l_start = 0; 94 | fl.l_len = 0; 95 | fl.l_type = F_UNLCK; 96 | int ret = fcntl(handle(), F_SETLKW, &fl); 97 | 98 | if (ret == -1) { 99 | qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); 100 | return false; 101 | } 102 | 103 | m_lock_mode = NoLock; 104 | return true; 105 | } 106 | 107 | QtLockedFile::~QtLockedFile() { 108 | if (isOpen()) 109 | unlock(); 110 | } 111 | -------------------------------------------------------------------------------- /example/Core/StyleManager/StyleManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * StyleManager.cpp - StyleManager Class 4 | * 5 | */ 6 | 7 | #include 8 | 9 | QString StyleManager::getStyleSheet( QString widget ) { 10 | 11 | QFile file( qApp->tr( ":/StyleSheets/%1.qss" ).arg( widget ) ); 12 | if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) 13 | return QString(); 14 | 15 | QString QSS = QString::fromLocal8Bit( file.readAll() ); 16 | file.close(); 17 | 18 | return QSS; 19 | }; 20 | 21 | QPalette StyleManager::transparentPalette() { 22 | 23 | QPalette pltt = qApp->palette(); 24 | 25 | pltt.setColor( QPalette::Active, QPalette::Window, Qt::transparent ); 26 | pltt.setColor( QPalette::Active, QPalette::WindowText, Qt::white ); 27 | pltt.setColor( QPalette::Active, QPalette::Base, Qt::transparent ); 28 | pltt.setColor( QPalette::Active, QPalette::AlternateBase, Qt::transparent ); 29 | pltt.setColor( QPalette::Active, QPalette::ToolTipBase, QColor( 0, 0, 0, 206 ) ); 30 | pltt.setColor( QPalette::Active, QPalette::ToolTipText, QColor( 0x61, 0x93, 0xCF ) ); 31 | pltt.setColor( QPalette::Active, QPalette::Text, Qt::white ); 32 | pltt.setColor( QPalette::Active, QPalette::Button, Qt::transparent ); 33 | pltt.setColor( QPalette::Active, QPalette::ButtonText, Qt::white ); 34 | pltt.setColor( QPalette::Active, QPalette::BrightText, Qt::white ); 35 | pltt.setColor( QPalette::Active, QPalette::Link, Qt::darkGreen ); 36 | 37 | pltt.setColor( QPalette::Disabled, QPalette::Window, Qt::transparent ); 38 | pltt.setColor( QPalette::Disabled, QPalette::WindowText, Qt::white ); 39 | pltt.setColor( QPalette::Disabled, QPalette::Base, Qt::transparent ); 40 | pltt.setColor( QPalette::Disabled, QPalette::AlternateBase, Qt::transparent ); 41 | pltt.setColor( QPalette::Disabled, QPalette::ToolTipBase, QColor( 0, 0, 0, 206 ) ); 42 | pltt.setColor( QPalette::Disabled, QPalette::ToolTipText, QColor( 0x61, 0x93, 0xCF ) ); 43 | pltt.setColor( QPalette::Disabled, QPalette::Text, Qt::white ); 44 | pltt.setColor( QPalette::Disabled, QPalette::Button, Qt::transparent ); 45 | pltt.setColor( QPalette::Disabled, QPalette::ButtonText, Qt::white ); 46 | pltt.setColor( QPalette::Disabled, QPalette::BrightText, Qt::white ); 47 | pltt.setColor( QPalette::Disabled, QPalette::Link, Qt::darkGreen ); 48 | 49 | pltt.setColor( QPalette::Inactive, QPalette::Window, Qt::transparent ); 50 | pltt.setColor( QPalette::Inactive, QPalette::WindowText, Qt::white ); 51 | pltt.setColor( QPalette::Inactive, QPalette::Base, Qt::transparent ); 52 | pltt.setColor( QPalette::Inactive, QPalette::AlternateBase, Qt::transparent ); 53 | pltt.setColor( QPalette::Inactive, QPalette::ToolTipBase, QColor( 0, 0, 0, 206 ) ); 54 | pltt.setColor( QPalette::Inactive, QPalette::ToolTipText, QColor( 0x61, 0x93, 0xCF ) ); 55 | pltt.setColor( QPalette::Inactive, QPalette::Text, Qt::white ); 56 | pltt.setColor( QPalette::Inactive, QPalette::Button, Qt::transparent ); 57 | pltt.setColor( QPalette::Inactive, QPalette::ButtonText, Qt::white ); 58 | pltt.setColor( QPalette::Inactive, QPalette::BrightText, Qt::white ); 59 | pltt.setColor( QPalette::Inactive, QPalette::Link, Qt::darkGreen ); 60 | 61 | return pltt; 62 | }; 63 | 64 | QPalette StyleManager::getPalette() { 65 | 66 | QPalette pltt = qApp->palette(); 67 | 68 | pltt.setColor( QPalette::Active, QPalette::Window, QColor( 30, 30, 30, 180 ) ); 69 | pltt.setColor( QPalette::Active, QPalette::WindowText, Qt::white ); 70 | pltt.setColor( QPalette::Active, QPalette::Base, Qt::transparent ); 71 | pltt.setColor( QPalette::Active, QPalette::AlternateBase, QColor( 30, 30, 30, 180 ) ); 72 | pltt.setColor( QPalette::Active, QPalette::ToolTipBase, QColor( 0, 0, 0, 206 ) ); 73 | pltt.setColor( QPalette::Active, QPalette::ToolTipText, QColor( 0x61, 0x93, 0xCF ) ); 74 | pltt.setColor( QPalette::Active, QPalette::Text, Qt::white ); 75 | pltt.setColor( QPalette::Active, QPalette::Button, Qt::transparent ); 76 | pltt.setColor( QPalette::Active, QPalette::ButtonText, Qt::white ); 77 | pltt.setColor( QPalette::Active, QPalette::BrightText, Qt::white ); 78 | pltt.setColor( QPalette::Active, QPalette::Link, Qt::darkGreen ); 79 | 80 | return pltt; 81 | }; 82 | -------------------------------------------------------------------------------- /lib/View/View.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is a part of PdfWidget. 4 | * PdfWidget is the default document viewer for the DesQ Suite 5 | * Copyright 2019-2021 Britanicus 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include 33 | #include "RenderOptions.hpp" 34 | 35 | class Zoom; 36 | class PageWidget; 37 | class QProgressBar; 38 | 39 | namespace PdfWidget { 40 | class Document; 41 | class Navigation; 42 | class Renderer; 43 | class ViewPrivate; 44 | 45 | class View : public QAbstractScrollArea { 46 | Q_OBJECT; 47 | 48 | Q_PROPERTY( PdfWidget::Document* document READ document WRITE setDocument NOTIFY documentChanged ); 49 | 50 | Q_PROPERTY( PageMode pageMode READ pageMode WRITE setPageMode NOTIFY pageModeChanged ); 51 | Q_PROPERTY( ZoomMode zoomMode READ zoomMode WRITE setZoomMode NOTIFY zoomModeChanged ); 52 | Q_PROPERTY( qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged ); 53 | Q_PROPERTY( PdfWidget::RenderOptions renderOptions READ renderOptions WRITE setRenderOptions NOTIFY renderOptionsChanged ); 54 | 55 | Q_PROPERTY( int pageSpacing READ pageSpacing WRITE setPageSpacing NOTIFY pageSpacingChanged ); 56 | Q_PROPERTY( QMargins documentMargins READ documentMargins WRITE setDocumentMargins NOTIFY documentMarginsChanged ); 57 | 58 | public: 59 | enum PageMode { 60 | SinglePage, 61 | MultiPage 62 | }; 63 | Q_ENUM( PageMode ); 64 | 65 | enum ZoomMode { 66 | CustomZoom, 67 | FitToWidth, 68 | FitInView 69 | }; 70 | Q_ENUM( ZoomMode ); 71 | 72 | enum Backend { 73 | PopplerRenderBackend, 74 | MuPdfRenderBackend 75 | }; 76 | Q_ENUM( Backend ); 77 | 78 | explicit View( QWidget *parent = nullptr ); 79 | ~View(); 80 | 81 | void loadDocument( QString path, PdfWidget::View::Backend ); 82 | void setDocument( PdfWidget::Document *document ); 83 | PdfWidget::Document *document() const; 84 | 85 | PdfWidget::Navigation *pageNavigation() const; 86 | 87 | PageMode pageMode() const; 88 | ZoomMode zoomMode() const; 89 | qreal zoomFactor() const; 90 | PdfWidget::RenderOptions renderOptions() const; 91 | 92 | int pageSpacing() const; 93 | void setPageSpacing( int spacing ); 94 | 95 | QMargins documentMargins() const; 96 | void setDocumentMargins( QMargins margins ); 97 | 98 | public Q_SLOTS: 99 | void setPageMode( PageMode mode ); 100 | void setZoomMode( ZoomMode mode ); 101 | void setZoomFactor( qreal factor ); 102 | void setRenderOptions( PdfWidget::RenderOptions opts ); 103 | 104 | Q_SIGNALS: 105 | void documentChanged( PdfWidget::Document *document ); 106 | void pageModeChanged( PageMode pageMode ); 107 | void zoomModeChanged( ZoomMode zoomMode ); 108 | void zoomFactorChanged( qreal zoomFactor ); 109 | void renderOptionsChanged( PdfWidget::RenderOptions opts ); 110 | void pageSpacingChanged( int pageSpacing ); 111 | void documentMarginsChanged( QMargins documentMargins ); 112 | 113 | void documentLoadingFailed(); 114 | 115 | protected: 116 | explicit View( ViewPrivate &, QWidget * ); 117 | 118 | void paintEvent( QPaintEvent *event ) override; 119 | void resizeEvent( QResizeEvent *event ) override; 120 | void scrollContentsBy( int dx, int dy ) override; 121 | 122 | void keyPressEvent( QKeyEvent *kEvent ); 123 | 124 | void wheelEvent( QWheelEvent *wEvent ); 125 | 126 | private: 127 | Q_DECLARE_PRIVATE( View ); 128 | 129 | Zoom *mZoomBtn; 130 | PageWidget *mPagesBtn; 131 | QProgressBar *progress; 132 | }; 133 | } 134 | -------------------------------------------------------------------------------- /example/Gui/Widgets/Misc/GuiWidgets.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * GuiWidgets.cpp - Gui Widgets for MiniPDF 4 | * 5 | */ 6 | 7 | #include "GuiWidgets.hpp" 8 | 9 | QWidget* Separator::vertical( QWidget *parent ) { 10 | 11 | return new Separator( Separator::Vertical, parent ); 12 | }; 13 | 14 | QWidget* Separator::horizontal( QWidget *parent ) { 15 | 16 | return new Separator( Separator::Horizontal, parent ); 17 | 18 | QWidget *hSep = new QWidget( parent ); 19 | hSep->setContentsMargins( QMargins() ); 20 | hSep->setFixedHeight( 1 ); 21 | hSep->setStyleSheet( "background-color: gray;" ); 22 | 23 | return hSep; 24 | }; 25 | 26 | Separator::Separator( Separator::Mode mode, QWidget *parent ) : QWidget( parent ) { 27 | 28 | mMode = mode; 29 | 30 | switch( mode ) { 31 | case Separator::Horizontal: { 32 | setContentsMargins( QMargins() ); 33 | setFixedHeight( 1 ); 34 | 35 | hGrad = QLinearGradient( QPoint( 0, 0 ), QPoint( 2000, 0 ) ); 36 | hGrad.setColorAt( 0.0, Qt::transparent ); 37 | hGrad.setColorAt( 0.4, Qt::gray ); 38 | hGrad.setColorAt( 0.6, Qt::gray ); 39 | hGrad.setColorAt( 1.0, Qt::transparent ); 40 | 41 | break; 42 | }; 43 | 44 | case Separator::Vertical: { 45 | setContentsMargins( QMargins() ); 46 | setFixedWidth( 1 ); 47 | 48 | vGrad = QLinearGradient( QPoint( 0, 0 ), QPoint( 0, 2000 ) ); 49 | vGrad.setColorAt( 0.0, Qt::transparent ); 50 | vGrad.setColorAt( 0.4, Qt::gray ); 51 | vGrad.setColorAt( 0.6, Qt::gray ); 52 | vGrad.setColorAt( 1.0, Qt::transparent ); 53 | 54 | break; 55 | } 56 | } 57 | }; 58 | 59 | void Separator::resizeEvent( QResizeEvent *rEvent ) { 60 | 61 | QWidget::resizeEvent( rEvent ); 62 | rEvent->accept(); 63 | 64 | switch( mMode ) { 65 | case Separator::Horizontal : { 66 | hGrad.setFinalStop( 0, rEvent->size().width() ); 67 | break; 68 | } 69 | 70 | case Separator::Vertical : { 71 | vGrad.setFinalStop( 0, rEvent->size().height() ); 72 | break; 73 | } 74 | } 75 | 76 | repaint(); 77 | }; 78 | 79 | void Separator::paintEvent( QPaintEvent *pEvent ) { 80 | 81 | QPainter *painter = new QPainter( this ); 82 | painter->setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing ); 83 | 84 | switch( mMode ) { 85 | case Separator::Horizontal : { 86 | hGrad.setFinalStop( 0, width() ); 87 | 88 | // painter->setPen( QPen( QBrush( hGrad ), 1.0 ) ); 89 | painter->setPen( QPen( Qt::gray, 1.0 ) ); 90 | painter->drawLine( 0, 0, width(), 0 ); 91 | break; 92 | } 93 | 94 | case Separator::Vertical : { 95 | vGrad.setFinalStop( 0, height() ); 96 | 97 | painter->setPen( QPen( QBrush( vGrad ), 1.0 ) ); 98 | painter->drawLine( rect().topLeft(), rect().bottomLeft() ); 99 | break; 100 | } 101 | } 102 | 103 | painter->end(); 104 | 105 | pEvent->accept(); 106 | }; 107 | 108 | QWidget* Spacer::vertical( int space, QWidget *parent ) { 109 | 110 | QWidget *spacer = new QWidget( parent ); 111 | if ( space > 0 ) 112 | spacer->setFixedHeight( space ); 113 | 114 | return spacer; 115 | }; 116 | 117 | QWidget* Spacer::horizontal( int space, QWidget *parent ) { 118 | 119 | QWidget *spacer = new QWidget( parent ); 120 | if ( space > 0 ) 121 | spacer->setFixedWidth( space ); 122 | 123 | return spacer; 124 | }; 125 | 126 | QWidget* Stretch::vertical( QWidget *parent ) { 127 | 128 | QWidget *vSpace = new QWidget( parent ); 129 | vSpace->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding ); 130 | vSpace->setContentsMargins( QMargins() ); 131 | 132 | return vSpace; 133 | }; 134 | 135 | QWidget* Stretch::horizontal( QWidget *parent ) { 136 | 137 | QWidget *hSpace = new QWidget( parent ); 138 | hSpace->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); 139 | hSpace->setContentsMargins( QMargins() ); 140 | 141 | return hSpace; 142 | }; 143 | 144 | LedLight::LedLight( quint64 radius, QWidget *parent ) : QWidget( parent ) { 145 | 146 | mRadius = radius; 147 | setMinimumSize( radius * 2, radius * 2 ); 148 | }; 149 | 150 | bool LedLight::isSafe() { 151 | 152 | return mSafe; 153 | }; 154 | 155 | void LedLight::setSafe( bool sfty ) { 156 | 157 | mSafe = sfty; 158 | 159 | repaint(); 160 | }; 161 | 162 | void LedLight::setModified( bool modified ) { 163 | 164 | mSafe = not modified; 165 | repaint(); 166 | }; 167 | 168 | void LedLight::paintEvent( QPaintEvent *pEvent ) { 169 | 170 | QPainter painter( this ); 171 | 172 | painter.setRenderHints( QPainter::Antialiasing ); 173 | 174 | painter.setPen( QPen( Qt::lightGray, 1.0 ) ); 175 | QColor color; 176 | if ( mSafe ) 177 | color = Qt::darkGreen; 178 | 179 | else 180 | color = Qt::red; 181 | 182 | QRadialGradient rg( QPoint( mRadius, mRadius ), mRadius, QPoint( width() / 2, mRadius / 2 ) ); 183 | rg.setColorAt( 0, Qt::white ); 184 | rg.setColorAt( 0.8, color.lighter( 120 ) ); 185 | rg.setColorAt( 1, color ); 186 | 187 | painter.setBrush( rg ); 188 | 189 | painter.drawEllipse( QRectF( ( width() - 2 * mRadius ) / 2, ( height() - 2 * mRadius ) / 2, 2 * mRadius, 2 * mRadius ) ); 190 | painter.end(); 191 | 192 | pEvent->accept(); 193 | }; 194 | -------------------------------------------------------------------------------- /lib/Document/Document.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project (https://gitlab.com/desq/) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "RenderOptions.hpp" 37 | 38 | namespace PdfWidget { 39 | 40 | class Page; 41 | class Document; 42 | typedef QList Pages; 43 | } 44 | 45 | class PdfWidget::Document : public QObject { 46 | Q_OBJECT; 47 | 48 | public: 49 | enum Status { 50 | Null, 51 | Loading, 52 | Ready, 53 | Unloading, 54 | Error 55 | }; 56 | Q_ENUM( Status ) 57 | 58 | enum DocumentError { 59 | NoError, 60 | UnknownError, 61 | FileNotFoundError, 62 | InvalidFileFormatError, 63 | IncorrectPasswordError, 64 | UnsupportedSecuritySchemeError 65 | }; 66 | Q_ENUM( DocumentError ) 67 | 68 | enum MetaDataField { 69 | Title, 70 | Subject, 71 | Author, 72 | Keywords, 73 | Producer, 74 | Creator, 75 | CreationDate, 76 | ModificationDate 77 | }; 78 | Q_ENUM( MetaDataField ) 79 | 80 | Document( QString docPath ); 81 | 82 | /* Check if a password is needed */ 83 | virtual bool passwordNeeded() const; 84 | 85 | /* Set a password */ 86 | virtual void setPassword( QString password ) = 0; 87 | 88 | /* Document File Name and File Path */ 89 | virtual QString fileName() const; 90 | virtual QString filePath() const; 91 | 92 | /* Pdf Info / Metadata */ 93 | virtual QString title() const = 0; 94 | virtual QString author() const = 0; 95 | virtual QString creator() const = 0; 96 | virtual QString producer() const = 0; 97 | virtual QString created() const = 0; 98 | 99 | /* Number of pages */ 100 | int pageCount() const; 101 | 102 | /* Size of the page */ 103 | QSizeF pageSize( int pageNo ) const; 104 | 105 | /* Reload the current document */ 106 | void reload(); 107 | 108 | /* PDF load status */ 109 | Document::Status status() const; 110 | 111 | /* Render and return a page */ 112 | QImage renderPage( int, QSize, RenderOptions ) const; 113 | QImage renderPage( int, qreal zoomFactor, RenderOptions ) const; 114 | 115 | /* Page Related */ 116 | Pages pages() const; 117 | Page* page( int pageNo ) const; 118 | QImage pageThumbnail( int pageNo ) const; 119 | 120 | /* Page Text */ 121 | QString pageText( int pageNo ) const; 122 | 123 | /* Text of a Selection rectangle */ 124 | QString text( int pageNo, QRectF ) const; 125 | 126 | /* Search for @query in @pageNo or all pages */ 127 | QList search( QString query, int pageNo, RenderOptions opts ) const; 128 | 129 | qreal zoomForWidth( int pageNo, qreal width ) const; 130 | qreal zoomForHeight( int pageNo, qreal width ) const; 131 | 132 | void setZoom( qreal zoom ); 133 | 134 | public Q_SLOTS: 135 | virtual void load() = 0; 136 | virtual void close() = 0; 137 | 138 | protected: 139 | QString mDocPath; 140 | Pages mPages; 141 | 142 | mutable QList searchRects; 143 | 144 | qreal mZoom; 145 | 146 | Status mStatus; 147 | DocumentError mDocError; 148 | bool mPassNeeded; 149 | 150 | Q_SIGNALS: 151 | void passwordRequired(); 152 | void reloadDocument(); 153 | void statusChanged( Document::Status status ); 154 | void pageCountChanged( int pageCount ); 155 | 156 | void loading( int ); 157 | }; 158 | 159 | class PdfWidget::Page { 160 | 161 | public: 162 | Page( int ); 163 | 164 | /* Page number of this page */ 165 | int pageNo(); 166 | 167 | /* Render and return a page */ 168 | virtual QImage render( QSize, RenderOptions ) const = 0; 169 | virtual QImage render( qreal zoomFactor, RenderOptions ) const = 0; 170 | 171 | /* Page Text */ 172 | virtual QString pageText() const = 0; 173 | 174 | /* Text of a Selection rectangle */ 175 | virtual QString text( QRectF ) const = 0; 176 | 177 | /* Search for @query in @pageNo or all pages */ 178 | virtual QList search( QString query, RenderOptions opts ) const = 0; 179 | 180 | /* Size of the page */ 181 | virtual QSizeF pageSize( qreal zoom = 1.0 ) const = 0; 182 | 183 | /* Thumbnail of the page */ 184 | virtual QImage thumbnail() const = 0; 185 | 186 | private: 187 | int mPageNo = -1; 188 | }; 189 | -------------------------------------------------------------------------------- /example/Gui/Widgets/RecentFiles/RecentFilesWidget.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * * RecentFiles.cpp - MiniPDF's RecentFiles 4 | * 5 | */ 6 | 7 | #include "RecentFilesWidget.hpp" 8 | #include "MessageDialog.hpp" 9 | 10 | RecentFile::RecentFile( QString path ) : QPushButton() { 11 | 12 | setToolTip( path ); 13 | 14 | QFileInfo info( path ); 15 | 16 | mName = baseName( path ); 17 | mIcon = getPixmap( path ); 18 | mDate = info.lastModified().toString( "ddd, MMM dd, yyyy hh:mm:ss AP" ); 19 | mSize = formatSize( info.size() ); 20 | 21 | setFixedSize( 270, 64 ); 22 | setCheckable( true ); 23 | setChecked( false ); 24 | 25 | setFocusPolicy( Qt::NoFocus ); 26 | }; 27 | 28 | QString RecentFile::file() { 29 | 30 | return toolTip(); 31 | }; 32 | 33 | void RecentFile::paintEvent( QPaintEvent *pEvent ) { 34 | 35 | QPushButton::paintEvent( pEvent ); 36 | QPainter painter( this ); 37 | 38 | if ( isChecked() ) { 39 | /* HighLight color */ 40 | QColor highlight = palette().color( QPalette::Highlight ); 41 | highlight.setAlpha( 150 ); 42 | 43 | painter.save(); 44 | painter.setPen( Qt::NoPen ); 45 | painter.setBrush( highlight ); 46 | painter.drawRoundedRect( QRectF( rect() ).adjusted( 1.5, 1.5, 0, 0 ), 2.0, 2.0 ); 47 | painter.restore(); 48 | 49 | painter.setPen( palette().color( QPalette::HighlightedText ) ); 50 | } 51 | 52 | painter.drawPixmap( QRect( 8, 8, 48, 48 ), mIcon.pixmap( 48 ) ); 53 | 54 | painter.drawText( QRect( 64, 9, 206, 16 ), Qt::AlignVCenter | Qt::AlignLeft, mName ); 55 | painter.drawText( QRect( 64, 25, 206, 16 ), Qt::AlignVCenter | Qt::AlignLeft, mSize ); 56 | painter.drawText( QRect( 64, 41, 206, 16 ), Qt::AlignVCenter | Qt::AlignLeft, mDate ); 57 | painter.end(); 58 | 59 | pEvent->accept(); 60 | }; 61 | 62 | RecentFiles::RecentFiles( QWidget *parent ) : QWidget( parent ) { 63 | 64 | stackLyt = new QStackedLayout(); 65 | 66 | QStringList recentList; 67 | Q_FOREACH( QString recent, settings.value( "Recent" ).toStringList() ) { 68 | if ( QFile::exists( recent ) ) 69 | recentList << recent; 70 | } 71 | 72 | /* recentList Files Layout */ 73 | QGridLayout *recentLyt = new QGridLayout(); 74 | 75 | for( int i = 0; i < recentList.count(); i++ ) { 76 | RecentFile *btn = new RecentFile( recentList[ i ] ); 77 | 78 | if ( i % 2 == 0 ) 79 | recentLyt->addWidget( btn, i / 2, 0 ); 80 | 81 | else 82 | recentLyt->addWidget( btn, i / 2, 1 ); 83 | } 84 | 85 | QPushButton *openSelBtn = new QPushButton( QIcon::fromTheme( "document-open" ), "Open &Selected" ); 86 | openSelBtn->setFixedWidth( 140 ); 87 | connect( openSelBtn, SIGNAL( clicked() ), this, SLOT( openFiles() ) ); 88 | 89 | QPushButton *clearRecentBtn = new QPushButton( QIcon( ":/icons/clear.png" ), "&Clear Recent" ); 90 | clearRecentBtn->setFixedWidth( 140 ); 91 | connect( clearRecentBtn, SIGNAL( clicked() ), this, SLOT( clearRecents() ) ); 92 | 93 | QPushButton *openBtn = new QPushButton( QIcon::fromTheme( "document-open" ), "&Open" ); 94 | openBtn->setFixedWidth( 140 ); 95 | connect( openBtn, SIGNAL( clicked() ), this, SIGNAL( open() ) ); 96 | 97 | QVBoxLayout *btnLyt = new QVBoxLayout(); 98 | 99 | btnLyt->addStretch(); 100 | btnLyt->addWidget( openSelBtn ); 101 | btnLyt->addWidget( clearRecentBtn ); 102 | btnLyt->addStretch(); 103 | btnLyt->addWidget( openBtn ); 104 | btnLyt->addStretch(); 105 | 106 | QHBoxLayout *baseLyt1 = new QHBoxLayout(); 107 | baseLyt1->addLayout( recentLyt ); 108 | baseLyt1->addWidget( Separator::vertical() ); 109 | baseLyt1->addLayout( btnLyt ); 110 | 111 | QWidget *baseWidget1 = new QWidget(); 112 | baseWidget1->setLayout( baseLyt1 ); 113 | 114 | QPushButton *openBtn2 = new QPushButton( QIcon::fromTheme( "document-open" ), "&Open" ); 115 | openBtn2->setFixedWidth( 140 ); 116 | connect( openBtn2, SIGNAL( clicked() ), this, SIGNAL( open() ) ); 117 | 118 | QVBoxLayout *baseLyt2 = new QVBoxLayout(); 119 | baseLyt2->addStretch(); 120 | baseLyt2->addWidget( openBtn2, 0, Qt::AlignCenter ); 121 | baseLyt2->addStretch(); 122 | 123 | QWidget *baseWidget2 = new QWidget(); 124 | baseWidget2->setLayout( baseLyt2 ); 125 | 126 | stackLyt->addWidget( baseWidget1 ); 127 | stackLyt->addWidget( baseWidget2 ); 128 | 129 | setLayout( stackLyt ); 130 | 131 | if ( recentList.count() ) 132 | stackLyt->setCurrentIndex( 0 ); 133 | 134 | else 135 | stackLyt->setCurrentIndex( 1 ); 136 | }; 137 | 138 | void RecentFiles::openFiles() { 139 | 140 | QStringList files; 141 | QList rfBtns = findChildren(); 142 | Q_FOREACH( RecentFile *rBtn, rfBtns ) 143 | if ( rBtn->isChecked() ) { 144 | files << rBtn->file(); 145 | rBtn->setChecked( false ); 146 | } 147 | 148 | if ( files.count() ) 149 | emit open( files.join( ";;" ) ); 150 | }; 151 | 152 | void RecentFiles::clearRecents() { 153 | 154 | int ret = MessageDialog::question( 155 | this, 156 | "MiniPDF - Clear Recents List?", 157 | "You are about to clear the list of recent files. This action can not be undone. Do you want to proceed?", 158 | QList() << MessageDialog::Yes << MessageDialog::No 159 | ); 160 | 161 | if ( ret == MessageDialog::No ) 162 | return; 163 | 164 | settings.setValue( "Recent", QStringList() ); 165 | settings.sync(); 166 | 167 | stackLyt->setCurrentIndex( 1 ); 168 | }; 169 | -------------------------------------------------------------------------------- /lib/Document/Document.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project (https://gitlab.com/desq/) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #include 31 | 32 | #include "Document.hpp" 33 | 34 | /* 35 | * 36 | * Generic class to handle document 37 | * 38 | */ 39 | 40 | PdfWidget::Document::Document( QString path ) : QObject() { 41 | 42 | mZoom = 1.0; 43 | mStatus = Null; 44 | mDocError = NoError; 45 | mPassNeeded = false; 46 | 47 | mDocPath = QFileInfo( path ).absoluteFilePath(); 48 | 49 | QFileSystemWatcher *fsw = new QFileSystemWatcher(); 50 | fsw->addPath( mDocPath ); 51 | connect( 52 | fsw, &QFileSystemWatcher::fileChanged, [=]( QString file ) { 53 | /* File deleted and created again: add it to the watcher */ 54 | if ( not fsw->files().contains( file ) and QFile::exists( file ) ) 55 | fsw->addPath( file ); 56 | 57 | reload(); 58 | } 59 | ); 60 | }; 61 | 62 | QString PdfWidget::Document::fileName() const { 63 | 64 | return DesQ::Utils::baseName( mDocPath ); 65 | }; 66 | 67 | QString PdfWidget::Document::filePath() const { 68 | 69 | return DesQ::Utils::dirName( mDocPath ); 70 | }; 71 | 72 | bool PdfWidget::Document::passwordNeeded() const { 73 | 74 | return mPassNeeded; 75 | }; 76 | 77 | int PdfWidget::Document::pageCount() const { 78 | 79 | return mPages.count(); 80 | }; 81 | 82 | QSizeF PdfWidget::Document::pageSize( int pageNo ) const { 83 | 84 | return mPages.at( pageNo )->pageSize() * mZoom; 85 | }; 86 | 87 | void PdfWidget::Document::reload() { 88 | 89 | mStatus = Null; 90 | mPages.clear(); 91 | 92 | load(); 93 | 94 | if ( mStatus == Ready ) { 95 | qDebug() << "Reload your pages.."; 96 | emit reloadDocument(); 97 | } 98 | }; 99 | 100 | PdfWidget::Document::Status PdfWidget::Document::status() const { 101 | 102 | return mStatus; 103 | }; 104 | 105 | QImage PdfWidget::Document::renderPage( int pageNo, QSize size, PdfWidget::RenderOptions opts ) const { 106 | 107 | if ( pageNo >= mPages.count() ) 108 | return QImage(); 109 | 110 | return mPages.at( pageNo )->render( size, opts ); 111 | }; 112 | 113 | QImage PdfWidget::Document::renderPage( int pageNo, qreal zoomFactor, PdfWidget::RenderOptions opts ) const { 114 | 115 | if ( pageNo >= mPages.count() ) 116 | return QImage(); 117 | 118 | return mPages.at( pageNo )->render( zoomFactor, opts ); 119 | }; 120 | 121 | PdfWidget::Pages PdfWidget::Document::pages() const { 122 | 123 | return mPages; 124 | }; 125 | 126 | PdfWidget::Page* PdfWidget::Document::page( int pageNo ) const { 127 | 128 | if ( pageNo >= mPages.count() ) 129 | return nullptr; 130 | 131 | return mPages.at( pageNo ); 132 | }; 133 | 134 | QImage PdfWidget::Document::pageThumbnail( int pageNo ) const { 135 | 136 | if ( pageNo >= mPages.count() ) 137 | return QImage(); 138 | 139 | return mPages.at( pageNo )->thumbnail(); 140 | }; 141 | 142 | QString PdfWidget::Document::pageText( int pageNo ) const { 143 | 144 | return mPages.at( pageNo )->text( QRectF() ); 145 | }; 146 | 147 | QString PdfWidget::Document::text( int pageNo, QRectF rect ) const { 148 | 149 | return mPages.at( pageNo )->text( rect ); 150 | }; 151 | 152 | QList PdfWidget::Document::search( QString query, int pageNo, PdfWidget::RenderOptions opts ) const { 153 | 154 | searchRects.clear(); 155 | 156 | if ( pageNo >= 0 or pageNo < mPages.count() ) { 157 | for( QRectF rect: mPages.at( pageNo )->search( query, opts ) ) { 158 | searchRects << QRect( rect.x() * mZoom, rect.y() * mZoom, rect.width() * mZoom, rect.height() * mZoom ); 159 | } 160 | } 161 | 162 | return searchRects; 163 | }; 164 | 165 | qreal PdfWidget::Document::zoomForWidth( int pageNo, qreal width ) const { 166 | 167 | if ( pageNo >= mPages.count() ) 168 | return 0.0; 169 | 170 | return 1.0 * width / mPages.at( pageNo )->pageSize().width(); 171 | }; 172 | 173 | qreal PdfWidget::Document::zoomForHeight( int pageNo, qreal height ) const { 174 | 175 | if ( pageNo >= mPages.count() ) 176 | return 0.0; 177 | 178 | return 1.0 * height / mPages.at( pageNo )->pageSize().height(); 179 | }; 180 | 181 | void PdfWidget::Document::setZoom( qreal zoom ) { 182 | 183 | mZoom = zoom; 184 | }; 185 | 186 | /* 187 | * 188 | * Generic class to handle document page 189 | * 190 | */ 191 | 192 | PdfWidget::Page::Page( int pgNo ) { 193 | 194 | mPageNo = pgNo; 195 | }; 196 | 197 | int PdfWidget::Page::pageNo() { 198 | 199 | return mPageNo; 200 | }; 201 | -------------------------------------------------------------------------------- /lib/Document/Navigation.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project ( https://gitlab.com/desq/ ) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #pragma once 31 | 32 | #include 33 | #include 34 | 35 | #include "Document.hpp" 36 | 37 | namespace PdfWidget { 38 | 39 | class Document; 40 | class Navigation; 41 | class NavigationPrivate; 42 | 43 | class Navigation : public QObject { 44 | 45 | Q_OBJECT; 46 | 47 | Q_PROPERTY( Document* document READ document WRITE setDocument NOTIFY documentChanged ) 48 | 49 | Q_PROPERTY( int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged ) 50 | Q_PROPERTY( int pageCount READ pageCount NOTIFY pageCountChanged ) 51 | Q_PROPERTY( bool canGoToPreviousPage READ canGoToPreviousPage NOTIFY canGoToPreviousPageChanged ) 52 | Q_PROPERTY( bool canGoToNextPage READ canGoToNextPage NOTIFY canGoToNextPageChanged ) 53 | 54 | public: 55 | explicit Navigation( QObject *parent = nullptr ); 56 | ~Navigation(); 57 | 58 | Document* document() const; 59 | void setDocument( Document *document ); 60 | 61 | int currentPage() const; 62 | void setCurrentPage( int currentPage ); 63 | 64 | int pageCount() const; 65 | 66 | bool canGoToPreviousPage() const; 67 | bool canGoToNextPage() const; 68 | 69 | public Q_SLOTS: 70 | void goToPreviousPage(); 71 | void goToNextPage(); 72 | 73 | Q_SIGNALS: 74 | void documentChanged( Document *document ); 75 | void currentPageChanged( int currentPage ); 76 | void pageCountChanged( int pageCount ); 77 | void canGoToPreviousPageChanged( bool canGo ); 78 | void canGoToNextPageChanged( bool canGo ); 79 | 80 | private: 81 | Q_DECLARE_PRIVATE( Navigation ); 82 | }; 83 | 84 | class NavigationPrivate : public QObjectPrivate { 85 | 86 | public: 87 | NavigationPrivate() : QObjectPrivate() { 88 | } 89 | 90 | void update() { 91 | 92 | Q_Q( Navigation ); 93 | 94 | const bool documentAvailable = m_document && m_document->status() == Document::Ready; 95 | 96 | if ( documentAvailable ) { 97 | const int newPageCount = m_document->pageCount(); 98 | if ( m_pageCount != newPageCount ) { 99 | m_pageCount = newPageCount; 100 | emit q->pageCountChanged( m_pageCount ); 101 | } 102 | } 103 | 104 | else { 105 | if ( m_pageCount != 0 ) { 106 | m_pageCount = 0; 107 | emit q->pageCountChanged( m_pageCount ); 108 | } 109 | } 110 | 111 | if ( m_currentPage != 0 ) { 112 | m_currentPage = 0; 113 | emit q->currentPageChanged( m_currentPage ); 114 | } 115 | 116 | updatePrevNext(); 117 | } 118 | 119 | void updatePrevNext() { 120 | 121 | Q_Q( Navigation ); 122 | 123 | const bool hasPreviousPage = m_currentPage > 0; 124 | const bool hasNextPage = m_currentPage < ( m_pageCount - 1 ); 125 | 126 | if ( m_canGoToPreviousPage != hasPreviousPage ) { 127 | 128 | m_canGoToPreviousPage = hasPreviousPage; 129 | emit q->canGoToPreviousPageChanged( m_canGoToPreviousPage ); 130 | } 131 | 132 | if ( m_canGoToNextPage != hasNextPage ) { 133 | 134 | m_canGoToNextPage = hasNextPage; 135 | emit q->canGoToNextPageChanged( m_canGoToNextPage ); 136 | } 137 | } 138 | 139 | void documentStatusChanged() { 140 | 141 | update(); 142 | } 143 | 144 | Q_DECLARE_PUBLIC( Navigation ); 145 | 146 | QPointer m_document = nullptr; 147 | int m_currentPage = 0; 148 | int m_pageCount = 0; 149 | bool m_canGoToPreviousPage = false; 150 | bool m_canGoToNextPage = false; 151 | 152 | QMetaObject::Connection m_documentStatusChangedConnection; 153 | }; 154 | } 155 | -------------------------------------------------------------------------------- /lib/PdfPrinter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * PdfPrinter.cpp - PDF printing class 4 | * 5 | */ 6 | 7 | #include 8 | #include "PdfPrinter.hpp" 9 | 10 | PdfPrinter::PdfPrinter( QString path, int curPg, QWidget *parent ) : QDialog( parent ) { 11 | 12 | mPdfDoc = QString( path ); 13 | mCurrentPage = curPg; 14 | setWindowTitle( "Print PDF Document" ); 15 | 16 | setupUI(); 17 | }; 18 | 19 | void PdfPrinter::setupUI() { 20 | 21 | /** Section 1 */ 22 | QLabel *printersLbl = new QLabel( "P&rinter:" ); 23 | printersCB = new QComboBox(); 24 | Q_FOREACH( QPrinterInfo pInfo, QPrinterInfo::availablePrinters() ) 25 | printersCB->addItem( pInfo.printerName() ); 26 | printersLbl->setBuddy( printersCB ); 27 | 28 | /** Section 2: Left Column */ 29 | pageRangeAllRB = new QRadioButton( "&All Pages" ); 30 | pageRangeAllRB->setChecked( true ); 31 | pageRangeCustomRB = new QRadioButton( "Pa&ges:" ); 32 | pageRangeCurrentRB = new QRadioButton( "C&urrent page" ); 33 | pageCustomLE = new QLineEdit(); 34 | pageCustomLE->setPlaceholderText( "For ex: 2,5-9,18" ); 35 | 36 | QGroupBox *pageRangeGB = new QGroupBox( "Print Range" ); 37 | QGridLayout *rangeLyt = new QGridLayout(); 38 | rangeLyt->addWidget( pageRangeAllRB, 0, 0, 1, 2 ); 39 | rangeLyt->addWidget( pageRangeCustomRB, 1, 0 ); 40 | rangeLyt->addWidget( pageCustomLE, 1, 1 ); 41 | rangeLyt->addWidget( pageRangeCurrentRB, 2, 0, 1, 2 ); 42 | pageRangeGB->setLayout( rangeLyt ); 43 | 44 | /** Section 2: Right Column */ 45 | singleRB = new QRadioButton( "&Single Side" ); 46 | singleRB->setChecked( true ); 47 | doubleRB = new QRadioButton( "&Back to back" ); 48 | 49 | QGroupBox *duplexGB = new QGroupBox( "Duplex Printing" ); 50 | QVBoxLayout *duplexLyt = new QVBoxLayout(); 51 | duplexLyt->addWidget( singleRB ); 52 | duplexLyt->addWidget( doubleRB ); 53 | duplexLyt->addWidget( new QLabel( " " ) ); 54 | duplexGB->setLayout( duplexLyt ); 55 | 56 | /** Section 3: Orientation */ 57 | potraitRB = new QRadioButton( "P&otrait" ); 58 | potraitRB->setChecked( true ); 59 | landscapeRB = new QRadioButton( "&Landscape" ); 60 | 61 | QGroupBox *orientGB = new QGroupBox( "Page Orientation" ); 62 | QHBoxLayout *orientLyt = new QHBoxLayout(); 63 | orientLyt->addWidget( potraitRB ); 64 | orientLyt->addWidget( landscapeRB ); 65 | orientGB->setLayout( orientLyt ); 66 | 67 | /** Section 4: Copies */ 68 | QLabel *copiesLbl = new QLabel( "&Number of copies:" ); 69 | copiesSB = new QSpinBox(); 70 | copiesSB->setRange( 1, 100 ); 71 | copiesLbl->setBuddy( copiesSB ); 72 | 73 | QGroupBox *outputGB = new QGroupBox( "Output Settings" ); 74 | QHBoxLayout *outputLyt = new QHBoxLayout(); 75 | outputLyt->addWidget( copiesLbl ); 76 | outputLyt->addWidget( copiesSB ); 77 | outputGB->setLayout( outputLyt ); 78 | 79 | /** Section 5: Buttons */ 80 | cancelBtn = new QPushButton( QIcon::fromTheme( "dialog-cancel" ), "&Cancel" ); 81 | connect( cancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); 82 | printBtn = new QPushButton( QIcon::fromTheme( "document-print" ), "&Print" ); 83 | connect( printBtn, SIGNAL( clicked() ), this, SLOT( print() ) ); 84 | 85 | QHBoxLayout *btnLyt = new QHBoxLayout(); 86 | btnLyt->addWidget( cancelBtn ); 87 | btnLyt->addStretch(); 88 | btnLyt->addWidget( printBtn ); 89 | 90 | QHBoxLayout *sec1Lyt = new QHBoxLayout(); 91 | sec1Lyt->addWidget( printersLbl ); 92 | sec1Lyt->addWidget( printersCB ); 93 | sec1Lyt->addStretch(); 94 | 95 | QHBoxLayout *sec2Lyt = new QHBoxLayout(); 96 | sec2Lyt->addWidget( pageRangeGB ); 97 | sec2Lyt->addWidget( duplexGB ); 98 | 99 | QHBoxLayout *sec3Lyt = new QHBoxLayout(); 100 | sec3Lyt->addWidget( orientGB ); 101 | 102 | QHBoxLayout *sec4Lyt = new QHBoxLayout(); 103 | sec4Lyt->addWidget( outputGB ); 104 | 105 | QHBoxLayout *sec5Lyt = new QHBoxLayout(); 106 | sec5Lyt->addWidget( cancelBtn ); 107 | sec5Lyt->addStretch(); 108 | sec5Lyt->addWidget( printBtn ); 109 | 110 | QVBoxLayout *baseLyt = new QVBoxLayout(); 111 | baseLyt->addLayout( sec1Lyt ); 112 | baseLyt->addLayout( sec2Lyt ); 113 | baseLyt->addLayout( sec3Lyt ); 114 | baseLyt->addLayout( sec4Lyt ); 115 | baseLyt->addLayout( sec5Lyt ); 116 | 117 | setLayout( baseLyt ); 118 | }; 119 | 120 | void PdfPrinter::print() { 121 | 122 | /** Printer and A4 paper */ 123 | QStringList lprOpts; 124 | lprOpts << "-P" << QString( "\"%1\"" ).arg( printersCB->currentText() ); 125 | lprOpts << "-h"; // No banners 126 | lprOpts << "-o" << "media=a4"; 127 | lprOpts << "-o" << "fit-to-page"; 128 | 129 | /** Page Range */ 130 | if ( pageRangeCustomRB->isChecked() ) 131 | lprOpts << "-o" << QString( "page-ranges=\"%1\"" ).arg( pageCustomLE->text() ); 132 | 133 | else if ( pageRangeCurrentRB->isChecked() ) 134 | lprOpts << "-o" << QString( "page-ranges=\"%1\"" ).arg( mCurrentPage ); 135 | 136 | // else /** By default all pages are printed */ 137 | // lprOpts << /** Nothing to be added here */ 138 | 139 | /** Orientation and duplexing: Potrait */ 140 | if ( potraitRB->isChecked() ) { 141 | lprOpts << "-o" << "potrait"; 142 | if ( doubleRB->isChecked() ) 143 | lprOpts << "-o" << "sides=two-sided-long-edge"; 144 | } 145 | 146 | /** Orientation and duplexing: Landscape */ 147 | else { 148 | lprOpts << "-o" << "landscape"; 149 | if ( doubleRB->isChecked() ) 150 | lprOpts << "-o" << "sides=two-sided-short-edge"; 151 | } 152 | 153 | /** Number of copies */ 154 | if ( copiesSB->value() > 1 ) { 155 | lprOpts << "-#" << QString::number( copiesSB->value() ); 156 | lprOpts << "-o" << "collate=true"; 157 | } 158 | 159 | lprOpts << mPdfDoc; 160 | 161 | printf( "lpr " ); 162 | Q_FOREACH( QString opt, lprOpts ) 163 | printf( "%s ", opt.toLocal8Bit().data() ); 164 | 165 | printf( "\n" ); 166 | 167 | QProcess::startDetached( "lpr", lprOpts ); 168 | 169 | accept(); 170 | }; 171 | -------------------------------------------------------------------------------- /lib/Poppler/PopplerDocument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is a part of PdfWidget. 4 | * PdfWidget is the default document viewer for the DesQ Suite 5 | * Copyright 2019-2021 Britanicus 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #include "PopplerDocument.hpp" 31 | 32 | PopplerDocument::PopplerDocument( QString pdfPath ) : PdfWidget::Document( pdfPath ) { 33 | 34 | mPdfDoc = nullptr; 35 | }; 36 | 37 | void PopplerDocument::setPassword( QString password ) { 38 | 39 | if ( mPdfDoc->unlock( password.toLatin1(), password.toLatin1() ) ) { 40 | 41 | mStatus = Error; 42 | mDocError = IncorrectPasswordError; 43 | 44 | qDebug() << "Invalid password. Please try again."; 45 | mPassNeeded = true; 46 | emit statusChanged( Error ); 47 | emit passwordRequired(); 48 | 49 | return; 50 | } 51 | 52 | mPassNeeded = false; 53 | mStatus = Loading; 54 | mDocError = NoError; 55 | 56 | emit statusChanged( Loading ); 57 | 58 | mPdfDoc->setRenderHint( Poppler::Document::Antialiasing ); 59 | mPdfDoc->setRenderHint( Poppler::Document::TextAntialiasing ); 60 | mPdfDoc->setRenderHint( Poppler::Document::TextHinting ); 61 | 62 | for( int i = 0; i < mPdfDoc->numPages(); i++ ) { 63 | Poppler::Page *p = mPdfDoc->page( i ); 64 | PdfPage *page = new PdfPage( p, i ); 65 | mPages.append( page ); 66 | 67 | emit loading( 1.0 * i / mPdfDoc->numPages() * 100.0 ); 68 | } 69 | 70 | mStatus = Ready; 71 | mDocError = NoError; 72 | 73 | emit statusChanged( Ready ); 74 | emit pageCountChanged( mPages.count() ); 75 | emit loading( 100 ); 76 | }; 77 | 78 | QString PopplerDocument::title() const { 79 | 80 | return mPdfDoc->title(); 81 | }; 82 | 83 | QString PopplerDocument::author() const { 84 | 85 | return mPdfDoc->author(); 86 | }; 87 | 88 | QString PopplerDocument::creator() const { 89 | 90 | return mPdfDoc->creator(); 91 | }; 92 | 93 | QString PopplerDocument::producer() const { 94 | 95 | return mPdfDoc->producer(); 96 | }; 97 | 98 | QString PopplerDocument::created() const { 99 | 100 | return mPdfDoc->creationDate().toString( "MMM DD, yyyy hh:mm:ss t AP" ); 101 | }; 102 | 103 | void PopplerDocument::load() { 104 | 105 | mStatus = Loading; 106 | emit statusChanged( Loading ); 107 | 108 | if ( not QFile::exists( mDocPath ) ) { 109 | mStatus = Error; 110 | mDocError = FileNotFoundError; 111 | emit statusChanged( Error ); 112 | 113 | return; 114 | } 115 | 116 | mPdfDoc = Poppler::Document::load( mDocPath ); 117 | 118 | if ( not mPdfDoc ) { 119 | mStatus = Error; 120 | mDocError = UnknownError; 121 | qDebug() << "Poppler::Document load failed"; 122 | emit statusChanged( Error ); 123 | 124 | return; 125 | } 126 | 127 | if ( mPdfDoc->isLocked() ) { 128 | mStatus = Error; 129 | mDocError = IncorrectPasswordError; 130 | qDebug() << "Poppler::Document is locked"; 131 | mPassNeeded = true; 132 | emit passwordRequired(); 133 | emit statusChanged( Error ); 134 | return; 135 | } 136 | 137 | mPdfDoc->setRenderHint( Poppler::Document::Antialiasing ); 138 | mPdfDoc->setRenderHint( Poppler::Document::TextAntialiasing ); 139 | mPdfDoc->setRenderHint( Poppler::Document::TextHinting ); 140 | 141 | for( int i = 0; i < mPdfDoc->numPages(); i++ ) { 142 | Poppler::Page *p = mPdfDoc->page( i ); 143 | PdfPage *page = new PdfPage( p, i ); 144 | mPages.append( page ); 145 | 146 | emit loading( 1.0 * i / mPdfDoc->numPages() * 100.0 ); 147 | } 148 | 149 | mStatus = Ready; 150 | mDocError = NoError; 151 | 152 | emit statusChanged( Ready ); 153 | emit pageCountChanged( mPages.count() ); 154 | emit loading( 100 ); 155 | }; 156 | 157 | void PopplerDocument::close() { 158 | 159 | mStatus = Unloading; 160 | mPages.clear(); 161 | mZoom = 1.0; 162 | 163 | delete mPdfDoc; 164 | }; 165 | 166 | 167 | PdfPage::PdfPage( Poppler::Page *pg, int pgNo ) : Page( pgNo ) { 168 | 169 | m_page = pg; 170 | }; 171 | 172 | QSizeF PdfPage::pageSize( qreal zoom ) const { 173 | 174 | return m_page->pageSizeF() * zoom; 175 | }; 176 | 177 | QImage PdfPage::thumbnail() const { 178 | 179 | return m_page->thumbnail(); 180 | }; 181 | 182 | QImage PdfPage::render( QSize pSize, PdfWidget::RenderOptions opts ) const { 183 | 184 | qreal wZoom = 1.0 * pSize.width() / m_page->pageSizeF().width(); 185 | qreal hZoom = 1.0 * pSize.height() / m_page->pageSizeF().height(); 186 | 187 | return m_page->renderToImage( 72 * wZoom, 72 * hZoom, -1, -1, -1, -1, ( Poppler::Page::Rotation )opts.rotation() ); 188 | }; 189 | 190 | QImage PdfPage::render( qreal zoomFactor, PdfWidget::RenderOptions opts ) const { 191 | 192 | return m_page->renderToImage( 72 * zoomFactor, 72 * zoomFactor, -1, -1, -1, -1, ( Poppler::Page::Rotation )opts.rotation() ); 193 | }; 194 | 195 | QString PdfPage::pageText() const { 196 | 197 | return text( QRectF() ); 198 | }; 199 | 200 | QString PdfPage::text( QRectF rect ) const { 201 | 202 | return m_page->text( rect ); 203 | }; 204 | 205 | QList PdfPage::search( QString query, PdfWidget::RenderOptions opts ) const { 206 | 207 | return m_page->search( 208 | query, // Search text 209 | Poppler::Page::IgnoreCase | Poppler::Page::IgnoreDiacritics, // Case insensitive 210 | ( Poppler::Page::Rotation )opts.rotation() // Rotation 211 | ); 212 | }; 213 | -------------------------------------------------------------------------------- /example/Gui/Application/qtlocalpeer.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 4 | ** All rights reserved. 5 | ** 6 | ** Contact: Nokia Corporation (qt-info@nokia.com) 7 | ** 8 | ** This file is part of a Qt Solutions component. 9 | ** 10 | ** You may use this file under the terms of the BSD license as follows: 11 | ** 12 | ** "Redistribution and use in source and binary forms, with or without 13 | ** modification, are permitted provided that the following conditions are 14 | ** met: 15 | ** * Redistributions of source code must retain the above copyright 16 | ** notice, this list of conditions and the following disclaimer. 17 | ** * Redistributions in binary form must reproduce the above copyright 18 | ** notice, this list of conditions and the following disclaimer in 19 | ** the documentation and/or other materials provided with the 20 | ** distribution. 21 | ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 22 | ** the names of its contributors may be used to endorse or promote 23 | ** products derived from this software without specific prior written 24 | ** permission. 25 | ** 26 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 37 | ** 38 | ****************************************************************************/ 39 | 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | #include 46 | #include 47 | 48 | #include "qtlockedfile.cpp" 49 | #include "qtlockedfile_unix.cpp" 50 | 51 | const char* QtLocalPeer::ack = "ack"; 52 | 53 | QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) 54 | : QObject(parent), id(appId) 55 | { 56 | QString prefix = id; 57 | if (id.isEmpty()) { 58 | id = QCoreApplication::applicationFilePath(); 59 | prefix = id.section(QLatin1Char('/'), -1); 60 | } 61 | prefix.remove(QRegExp("[^a-zA-Z]")); 62 | prefix.truncate(6); 63 | 64 | QByteArray idc = id.toUtf8(); 65 | quint16 idNum = qChecksum(idc.constData(), idc.size()); 66 | mSocketName = QLatin1String("minipdf-") + prefix 67 | + QLatin1Char('-') + QString::number(idNum, 16); 68 | 69 | mSocketName += QLatin1Char('-') + QString::number(getuid(), 16); 70 | 71 | server = new QLocalServer(this); 72 | QString lockName = QDir(QDir::tempPath()).absolutePath() 73 | + QLatin1Char('/') + mSocketName 74 | + QLatin1String("-lockfile"); 75 | lockFile.setFileName(lockName); 76 | lockFile.open(QIODevice::ReadWrite); 77 | } 78 | 79 | 80 | 81 | bool QtLocalPeer::isClient() 82 | { 83 | if (lockFile.isLocked()) 84 | return false; 85 | 86 | if (!lockFile.lock(QtLockedFile::WriteLock, false)) 87 | return true; 88 | 89 | bool res = server->listen(mSocketName); 90 | #if (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) 91 | // ### Workaround 92 | if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { 93 | QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+mSocketName); 94 | res = server->listen(mSocketName); 95 | } 96 | #endif 97 | if (!res) 98 | qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); 99 | QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection())); 100 | return false; 101 | } 102 | 103 | 104 | bool QtLocalPeer::sendMessage(const QString &message, int timeout) 105 | { 106 | if (!isClient()) 107 | return false; 108 | 109 | QLocalSocket socket; 110 | bool connOk = false; 111 | for(int i = 0; i < 2; i++) { 112 | // Try twice, in case the other instance is just starting up 113 | socket.connectToServer(mSocketName); 114 | connOk = socket.waitForConnected(timeout/2); 115 | if (connOk || i) 116 | break; 117 | int ms = 250; 118 | 119 | struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; 120 | nanosleep(&ts, NULL); 121 | } 122 | if (!connOk) 123 | return false; 124 | 125 | QByteArray uMsg(message.toUtf8()); 126 | QDataStream ds(&socket); 127 | ds.writeBytes(uMsg.constData(), uMsg.size()); 128 | bool res = socket.waitForBytesWritten(timeout); 129 | if (res) { 130 | res &= socket.waitForReadyRead(timeout); // wait for ack 131 | if (res) 132 | res &= (socket.read(qstrlen(ack)) == ack); 133 | } 134 | return res; 135 | } 136 | 137 | QString QtLocalPeer::socketName() { 138 | 139 | return mSocketName; 140 | } 141 | 142 | void QtLocalPeer::shutdown() { 143 | 144 | server->close(); 145 | lockFile.unlock(); 146 | } 147 | 148 | void QtLocalPeer::receiveConnection() { 149 | 150 | QLocalSocket* socket = server->nextPendingConnection(); 151 | if (!socket) 152 | return; 153 | 154 | while (socket->bytesAvailable() < (int)sizeof(quint32)) 155 | socket->waitForReadyRead(); 156 | QDataStream ds(socket); 157 | QByteArray uMsg; 158 | quint32 remaining; 159 | ds >> remaining; 160 | uMsg.resize(remaining); 161 | int got = 0; 162 | char* uMsgBuf = uMsg.data(); 163 | do { 164 | got = ds.readRawData(uMsgBuf, remaining); 165 | remaining -= got; 166 | uMsgBuf += got; 167 | } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); 168 | if (got < 0) { 169 | qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); 170 | delete socket; 171 | return; 172 | } 173 | QString message(QString::fromUtf8(uMsg)); 174 | socket->write(ack, qstrlen(ack)); 175 | socket->waitForBytesWritten(1000); 176 | delete socket; 177 | emit messageReceived(message); //### (might take a long time to return) 178 | } 179 | -------------------------------------------------------------------------------- /example/Gui/Application/qtlockedfile.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 4 | ** All rights reserved. 5 | ** 6 | ** Contact: Nokia Corporation (qt-info@nokia.com) 7 | ** 8 | ** This file is part of a Qt Solutions component. 9 | ** 10 | ** You may use this file under the terms of the BSD license as follows: 11 | ** 12 | ** "Redistribution and use in source and binary forms, with or without 13 | ** modification, are permitted provided that the following conditions are 14 | ** met: 15 | ** * Redistributions of source code must retain the above copyright 16 | ** notice, this list of conditions and the following disclaimer. 17 | ** * Redistributions in binary form must reproduce the above copyright 18 | ** notice, this list of conditions and the following disclaimer in 19 | ** the documentation and/or other materials provided with the 20 | ** distribution. 21 | ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 22 | ** the names of its contributors may be used to endorse or promote 23 | ** products derived from this software without specific prior written 24 | ** permission. 25 | ** 26 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 37 | ** 38 | ****************************************************************************/ 39 | 40 | #include 41 | 42 | /*! 43 | \class QtLockedFile 44 | 45 | \brief The QtLockedFile class extends QFile with advisory locking 46 | functions. 47 | 48 | A file may be locked in read or write mode. Multiple instances of 49 | \e QtLockedFile, created in multiple processes running on the same 50 | machine, may have a file locked in read mode. Exactly one instance 51 | may have it locked in write mode. A read and a write lock cannot 52 | exist simultaneously on the same file. 53 | 54 | The file locks are advisory. This means that nothing prevents 55 | another process from manipulating a locked file using QFile or 56 | file system functions offered by the OS. Serialization is only 57 | guaranteed if all processes that access the file use 58 | QLockedFile. Also, while holding a lock on a file, a process 59 | must not open the same file again (through any API), or locks 60 | can be unexpectedly lost. 61 | 62 | The lock provided by an instance of \e QtLockedFile is released 63 | whenever the program terminates. This is true even when the 64 | program crashes and no destructors are called. 65 | */ 66 | 67 | /*! \enum QtLockedFile::LockMode 68 | 69 | This enum describes the available lock modes. 70 | 71 | \value ReadLock A read lock. 72 | \value WriteLock A write lock. 73 | \value NoLock Neither a read lock nor a write lock. 74 | */ 75 | 76 | /*! 77 | Constructs an unlocked \e QtLockedFile object. This constructor 78 | behaves in the same way as \e QFile::QFile(). 79 | 80 | \sa QFile::QFile() 81 | */ 82 | QtLockedFile::QtLockedFile() : QFile() { 83 | 84 | m_lock_mode = NoLock; 85 | } 86 | 87 | /*! 88 | Constructs an unlocked QtLockedFile object with file \a name. This 89 | constructor behaves in the same way as \e QFile::QFile(const 90 | QString&). 91 | 92 | \sa QFile::QFile() 93 | */ 94 | QtLockedFile::QtLockedFile(const QString &name) : QFile(name) { 95 | 96 | m_lock_mode = NoLock; 97 | } 98 | 99 | /*! 100 | Opens the file in OpenMode \a mode. 101 | 102 | This is identical to QFile::open(), with the one exception that the 103 | Truncate mode flag is disallowed. Truncation would conflict with the 104 | advisory file locking, since the file would be modified before the 105 | write lock is obtained. If truncation is required, use resize(0) 106 | after obtaining the write lock. 107 | 108 | Returns true if successful; otherwise false. 109 | 110 | \sa QFile::open(), QFile::resize() 111 | */ 112 | bool QtLockedFile::open(OpenMode mode) { 113 | 114 | if (mode & QIODevice::Truncate) { 115 | qWarning("QtLockedFile::open(): Truncate mode not allowed."); 116 | return false; 117 | } 118 | return QFile::open(mode); 119 | } 120 | 121 | /*! 122 | Returns \e true if this object has a in read or write lock; 123 | otherwise returns \e false. 124 | 125 | \sa lockMode() 126 | */ 127 | bool QtLockedFile::isLocked() const { 128 | return m_lock_mode != NoLock; 129 | } 130 | 131 | /*! 132 | Returns the type of lock currently held by this object, or \e 133 | QtLockedFile::NoLock. 134 | 135 | \sa isLocked() 136 | */ 137 | QtLockedFile::LockMode QtLockedFile::lockMode() const { 138 | return m_lock_mode; 139 | } 140 | 141 | /*! 142 | \fn bool QtLockedFile::lock(LockMode mode, bool block = true) 143 | 144 | Obtains a lock of type \a mode. The file must be opened before it 145 | can be locked. 146 | 147 | If \a block is true, this function will block until the lock is 148 | aquired. If \a block is false, this function returns \e false 149 | immediately if the lock cannot be aquired. 150 | 151 | If this object already has a lock of type \a mode, this function 152 | returns \e true immediately. If this object has a lock of a 153 | different type than \a mode, the lock is first released and then a 154 | new lock is obtained. 155 | 156 | This function returns \e true if, after it executes, the file is 157 | locked by this object, and \e false otherwise. 158 | 159 | \sa unlock(), isLocked(), lockMode() 160 | */ 161 | 162 | /*! 163 | \fn bool QtLockedFile::unlock() 164 | 165 | Releases a lock. 166 | 167 | If the object has no lock, this function returns immediately. 168 | 169 | This function returns \e true if, after it executes, the file is 170 | not locked by this object, and \e false otherwise. 171 | 172 | \sa lock(), isLocked(), lockMode() 173 | */ 174 | 175 | /*! 176 | \fn QtLockedFile::~QtLockedFile() 177 | 178 | Destroys the \e QtLockedFile object. If any locks were held, they 179 | are released. 180 | */ 181 | -------------------------------------------------------------------------------- /example/Gui/UI/MiniPdf.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * MiniPdf.cpp - MiniPdf UI Class 4 | * 5 | */ 6 | 7 | // Local Headers 8 | #include "Global.hpp" 9 | #include "MiniPdf.hpp" 10 | #include "Tools.hpp" 11 | #include "FileDialog.hpp" 12 | #include "RecentFilesWidget.hpp" 13 | 14 | MiniPdf::MiniPdf() : QMainWindow() { 15 | 16 | // Setup base gui 17 | setWindowProperties(); 18 | setupGui(); 19 | setupConnections(); 20 | 21 | recentIdx = -1; 22 | 23 | if ( qApp->arguments().count() > 1 ) { 24 | 25 | filesQueue = qApp->arguments(); 26 | filesQueue.removeFirst(); 27 | loadFiles(); 28 | } 29 | 30 | else { 31 | 32 | openRecentFiles(); 33 | } 34 | }; 35 | 36 | void MiniPdf::setupGui() { 37 | 38 | // Setup the tab widget 39 | Tabs = new TabWidget( this ); 40 | 41 | QVBoxLayout *bLyt = new QVBoxLayout(); 42 | bLyt->setContentsMargins( 1, 1, 1, 1 ); 43 | bLyt->setSpacing( 0 ); 44 | 45 | bLyt->addWidget( Tabs ); 46 | 47 | QWidget *Base = new QWidget( this ); 48 | Base->setObjectName( "guiBase" ); 49 | Base->setLayout( bLyt ); 50 | 51 | setCentralWidget( Base ); 52 | }; 53 | 54 | void MiniPdf::setWindowProperties() { 55 | 56 | setWindowTitle( "MiniPdf" ); 57 | setWindowIcon( QIcon( ":/icons/minipdf.png" ) ); 58 | 59 | setWindowFlags( Qt::Window ); 60 | 61 | setMinimumSize( QSize( 800, 600 ) ); 62 | }; 63 | 64 | void MiniPdf::setupConnections() { 65 | 66 | /** Setup various connections to slots */ 67 | connect( Tabs, SIGNAL( tabCloseRequested( int ) ), this, SLOT( closeTab( int ) ) ); 68 | connect( Tabs, SIGNAL( open() ), this, SLOT( openFiles() ) ); 69 | 70 | /** Distraction-free mode */ 71 | QAction *dfreeAct = new QAction( QIcon( ":/icons/info.png" ), "D-Free Mode", this ); 72 | dfreeAct->setShortcut( QKeySequence( "Ctrl+Shift+D" ) ); 73 | connect( dfreeAct, SIGNAL( triggered() ), this, SLOT( dfreeMode() ) ); 74 | addAction( dfreeAct ); 75 | }; 76 | 77 | void MiniPdf::addToRecentList( QString file ) { 78 | 79 | QStringList recent = ::settings.value( "Recent" ).toStringList(); 80 | 81 | /* Add the just opened file to the list */ 82 | if ( recent.contains( file ) ) 83 | recent.move( recent.indexOf( file ), 0 ); 84 | 85 | else 86 | recent.prepend( QFileInfo( file ).absoluteFilePath() ); 87 | 88 | /* If we have more than 10 recent, remove the older ones */ 89 | while ( recent.count() > 10 ) 90 | recent.removeLast(); 91 | 92 | ::settings.setValue( "Recent", recent ); 93 | ::settings.sync(); 94 | }; 95 | 96 | void MiniPdf::openFiles() { 97 | 98 | if ( recentIdx >= 0 ) { 99 | Tabs->removeTab( recentIdx ); 100 | recentIdx = -1; 101 | } 102 | 103 | if ( Tabs->currentIndex() != recentIdx ) 104 | filesQueue << FileDialog::getOpenFileNames( this, dirName( openedFiles.at( Tabs->currentIndex() ) ) ); 105 | 106 | else 107 | filesQueue << FileDialog::getOpenFileNames( this, QDir::homePath() ); 108 | 109 | if ( !filesQueue.isEmpty() ) 110 | loadFiles(); 111 | 112 | if ( not Tabs->count() ) 113 | openRecentFiles(); 114 | }; 115 | 116 | void MiniPdf::openRecentFiles() { 117 | 118 | if ( recentIdx >= 0 ) { 119 | Tabs->setCurrentIndex( recentIdx ); 120 | return; 121 | } 122 | 123 | RecentFiles *rFiles = new RecentFiles( this ); 124 | 125 | connect( rFiles, SIGNAL( open() ), this, SLOT( openFiles() ) ); 126 | connect( rFiles, SIGNAL( open( QString ) ), this, SLOT( messageReciever( const QString ) ) ); 127 | 128 | recentIdx = Tabs->addTab( rFiles, QIcon( ":/icons/open-recent.png" ), "Recent Files" ); 129 | Tabs->setCurrentIndex( recentIdx ); 130 | Tabs->currentWidget()->setFocus(); 131 | }; 132 | 133 | void MiniPdf::loadFiles() { 134 | 135 | for( int i = 0; i < filesQueue.count(); i++ ) { 136 | if ( openedFiles.contains( filesQueue[ i ] ) ) 137 | continue; 138 | 139 | qDebug() << "Loading PDF:" << filesQueue[ i ]; 140 | PdfWidget::View *view = new PdfWidget::View( this ); 141 | 142 | Tabs->addTab( view, QIcon::fromTheme( "application-pdf", QIcon( ":/icons/pdf.png" ) ), baseName( filesQueue[ i ] ) ); 143 | openedFiles << filesQueue[ i ]; 144 | 145 | view->loadDocument( filesQueue[ i ], PdfWidget::View::MuPdfRenderBackend ); 146 | 147 | /* Add the just opened file to the list */ 148 | addToRecentList( filesQueue[ i ] ); 149 | } 150 | 151 | filesQueue.clear(); 152 | 153 | Tabs->setCurrentIndex( Tabs->count() - 1 ); 154 | qobject_cast( Tabs->currentWidget() )->setFocus(); 155 | }; 156 | 157 | void MiniPdf::reload() { 158 | 159 | qobject_cast( Tabs->currentWidget() )->document()->reload(); 160 | }; 161 | 162 | void MiniPdf::printFile() { 163 | 164 | }; 165 | 166 | void MiniPdf::settings() { 167 | 168 | wSettings *settingsDlg = new wSettings(); 169 | connect( settingsDlg, SIGNAL( fontSet() ), this, SLOT( setFont() ) ); 170 | settingsDlg->exec(); 171 | }; 172 | 173 | void MiniPdf::closeTab() { 174 | 175 | qWarning() << "Closing tab"; 176 | 177 | int idx = Tabs->currentIndex(); 178 | if ( idx == recentIdx ) { 179 | qWarning() << "Removing tab:" << idx; 180 | Tabs->removeTab( recentIdx ); 181 | recentIdx = -1; 182 | 183 | if ( not Tabs->count() ) { 184 | qWarning() << "Opening recent files"; 185 | openRecentFiles(); 186 | } 187 | 188 | return; 189 | } 190 | 191 | openedFiles.takeAt( idx ); 192 | Tabs->removeTab( Tabs->currentIndex() ); 193 | 194 | if ( Tabs->count() ) 195 | qobject_cast( Tabs->currentWidget() )->setFocus(); 196 | 197 | else 198 | openRecentFiles(); 199 | }; 200 | 201 | void MiniPdf::closeTab( int index ) { 202 | 203 | if ( index == recentIdx ) { 204 | Tabs->removeTab( recentIdx ); 205 | recentIdx = -1; 206 | 207 | if ( not Tabs->count() ) 208 | openRecentFiles(); 209 | 210 | return; 211 | } 212 | 213 | openedFiles.takeAt( index ); 214 | Tabs->removeTab( index ); 215 | 216 | if ( Tabs->count() ) 217 | qobject_cast( Tabs->currentWidget() )->setFocus(); 218 | 219 | else 220 | openRecentFiles(); 221 | }; 222 | 223 | void MiniPdf::closeAllTabs() { 224 | 225 | while ( Tabs->count() ) 226 | Tabs->removeTab( Tabs->currentIndex() ); 227 | 228 | openRecentFiles(); 229 | openedFiles.clear(); 230 | }; 231 | 232 | void MiniPdf::dfreeMode() { 233 | 234 | if ( Tabs->currentIndex() == recentIdx ) 235 | return; 236 | 237 | /** Hide the main window */ 238 | // hide(); 239 | 240 | /** Open the distraction-free widget */ 241 | PdfWidget::View *view = qobject_cast( Tabs->currentWidget() ); 242 | view->setParent( nullptr ); 243 | view->showFullScreen(); 244 | 245 | // int cIdx = Tabs->currentIndex(); 246 | // Tabs->removeTab( cIdx ); 247 | 248 | // Tabs->insertTab( cIdx, ed, getPixmap( ed->fileName() ), baseName( ed->fileName() ) ); 249 | 250 | /** Show the main window on exit */ 251 | // show(); 252 | }; 253 | 254 | void MiniPdf::messageReciever( QString msg ) { 255 | 256 | if ( recentIdx >= 0 ) { 257 | Tabs->removeTab( recentIdx ); 258 | recentIdx = -1; 259 | } 260 | 261 | if ( msg.count() ) { 262 | Q_FOREACH( QString file, msg.split( ";;" ) ) { 263 | if ( openedFiles.contains( file ) ) 264 | continue; 265 | 266 | PdfWidget::View *view = new PdfWidget::View( this ); 267 | 268 | int idx = Tabs->addTab( view, QIcon( getPixmap( file ) ) , baseName( file ) ); 269 | view->loadDocument( file, PdfWidget::View::MuPdfRenderBackend ); 270 | 271 | Tabs->setCurrentIndex( idx ); 272 | 273 | qobject_cast( Tabs->currentWidget() )->setFocus(); 274 | 275 | /* Add the just opened file to the list */ 276 | addToRecentList( file ); 277 | 278 | if ( not openedFiles.contains( file ) ) 279 | openedFiles << file; 280 | } 281 | } 282 | 283 | if ( not Tabs->count() ) 284 | openRecentFiles(); 285 | }; 286 | 287 | void MiniPdf::toggleMaximizeRestore() { 288 | 289 | if ( isMaximized() ) 290 | showNormal(); 291 | 292 | else 293 | showMaximized(); 294 | }; 295 | 296 | void MiniPdf::closeEvent( QCloseEvent *cEvent ) { 297 | 298 | for( int i = 0; i < Tabs->count(); i++ ) 299 | Tabs->removeTab( i ); 300 | 301 | cEvent->accept(); 302 | }; 303 | -------------------------------------------------------------------------------- /lib/Document/Renderer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2019-2021 Britanicus 4 | * 5 | * This file is a part of DesQ project (https://gitlab.com/desq/) 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 3 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #include "Renderer.hpp" 31 | #include "RendererImpl.hpp" 32 | #include "Document.hpp" 33 | 34 | RenderTask::RenderTask( PdfWidget::Page *pg, QSize imgSz, PdfWidget::RenderOptions opts, qint64 id ) { 35 | 36 | mPage = pg; 37 | mImgSize = imgSz; 38 | mOpts = opts; 39 | mId = id; 40 | }; 41 | 42 | int RenderTask::pageNumber() { 43 | 44 | return mPage->pageNo(); 45 | }; 46 | 47 | qint64 RenderTask::requestId() { 48 | 49 | return mId; 50 | }; 51 | 52 | QSize RenderTask::imageSize() { 53 | 54 | return mImgSize; 55 | }; 56 | 57 | void RenderTask::invalidate() { 58 | 59 | /* Set the request ID to -1. */ 60 | mId = -1; 61 | } 62 | 63 | void RenderTask::run() { 64 | 65 | /* If this task has been invalidated */ 66 | if ( mId < 0 ) 67 | return; 68 | 69 | QImage img = mPage->render( mImgSize, mOpts ); 70 | 71 | /* Emit only if the task is valid */ 72 | if ( mId > 0 ) 73 | emit imageReady( mPage->pageNo(), img, mId ); 74 | }; 75 | 76 | PdfWidget::Renderer::Renderer( QObject *parent ) : QObject( parent ) { 77 | 78 | mDoc = nullptr; 79 | }; 80 | 81 | void PdfWidget::Renderer::setDocument( PdfWidget::Document *doc ) { 82 | 83 | if ( mDoc == doc ) 84 | return; 85 | 86 | /* Clear the cache */ 87 | pageCache.clear(); 88 | pages.clear(); 89 | 90 | /* Clear the requests */ 91 | for( int rq = 0; rq < requests.count(); rq++ ) { 92 | RenderTask *task = requestCache.take( rq ); 93 | /* Invalidate */ 94 | task->invalidate(); 95 | 96 | /* Disconnect: Don't waste time validating it when it's complete */ 97 | task->disconnect(); 98 | 99 | /* Remove @pg from @requests */ 100 | requests.removeAll( rq ); 101 | } 102 | 103 | /* Clear the queue */ 104 | for( int q = 0; q < queue.count(); q++ ) { 105 | RenderTask *task = queuedRequests.take( q ); 106 | /* Invalidate */ 107 | task->invalidate(); 108 | 109 | /* Disconnect: Don't waste time validating it when it's complete */ 110 | task->disconnect(); 111 | 112 | /* Remove @pg from @requests */ 113 | queue.removeAll( q ); 114 | } 115 | 116 | mDoc = doc; 117 | validFrom = QDateTime::currentDateTime().toSecsSinceEpoch(); 118 | }; 119 | 120 | QImage PdfWidget::Renderer::requestPage( int pg, QSize imgSz, PdfWidget::RenderOptions opts ) { 121 | 122 | if ( pg >= mDoc->pageCount() ) 123 | return QImage(); 124 | 125 | /* Check if we have the image in the cache */ 126 | QImage img; 127 | if ( pages.contains( pg ) ) { 128 | /* Retrieve the image */ 129 | img = pageCache.value( pg ); 130 | 131 | /* If the image has proper size, return it */ 132 | if ( img.size() == imgSz ) 133 | return img; 134 | } 135 | 136 | /* Check if a request has already been made */ 137 | if ( requests.contains( pg ) ) { 138 | /* Get the request */ 139 | RenderTask *request = requestCache.value( pg ); 140 | QSize rq = request->imageSize(); 141 | 142 | /* If the image has proper size, return it */ 143 | if ( rq == imgSz ) 144 | return ( img.isNull() ? img : img.scaled( imgSz, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); 145 | 146 | /* Request is smaller. Invalidate it and remove from cache */ 147 | else { 148 | /* Invalidate */ 149 | request->invalidate(); 150 | 151 | /* Disconnect: Don't waste time validating it when it's complete */ 152 | request->disconnect(); 153 | 154 | /* Remove from cache */ 155 | requestCache.remove( pg ); 156 | 157 | /* Remove @pg from @requests */ 158 | requests.removeAll( pg ); 159 | } 160 | } 161 | 162 | /* Check if a request is in the queue */ 163 | if ( queue.contains( pg ) ) { 164 | /* Get the request */ 165 | RenderTask *request = queuedRequests.value( pg ); 166 | QSize rq = request->imageSize(); 167 | 168 | /* If the image has proper size, return it */ 169 | if ( rq == imgSz ) 170 | return ( img.isNull() ? img : img.scaled( imgSz, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); 171 | 172 | /* Requested image is smaller. Remove from the queue */ 173 | else { 174 | /* Invalidate */ 175 | request->invalidate(); 176 | 177 | /* Disconnect: Don't waste time validating it when it's complete */ 178 | request->disconnect(); 179 | 180 | /* Remove from queue */ 181 | queuedRequests.remove( pg ); 182 | 183 | /* Remove @pg from @queue */ 184 | queue.removeAll( pg ); 185 | } 186 | } 187 | 188 | RenderTask *task = new RenderTask( mDoc->page( pg ), imgSz, opts, QDateTime::currentDateTime().toSecsSinceEpoch() ); 189 | task->setAutoDelete( false ); 190 | 191 | connect( task, &RenderTask::imageReady, this, &PdfWidget::Renderer::validateImage ); 192 | 193 | /* Start rendering if there is an available slot */ 194 | if ( requests.count() < requestLimit ) { 195 | requests << pg; 196 | requestCache.insert( pg, task ); 197 | 198 | /* Start the rendering in a separate thread */ 199 | QThreadPool::globalInstance()->start( task ); 200 | } 201 | 202 | else { 203 | queue << pg; 204 | queuedRequests.insert( pg, task ); 205 | } 206 | 207 | return ( img.isNull() ? img : img.scaled( imgSz, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); 208 | }; 209 | 210 | void PdfWidget::Renderer::reload() { 211 | 212 | /* The document was reloaded: Clear the page cache */ 213 | pageCache.clear(); 214 | pages.clear(); 215 | 216 | /* Clear the requests */ 217 | for( int rq = 0; rq < requests.count(); rq++ ) { 218 | 219 | /* Get the render task */ 220 | RenderTask *task = requestCache.take( rq ); 221 | 222 | /* Invalidate */ 223 | task->invalidate(); 224 | 225 | /* Disconnect: Don't waste time validating it when it's complete */ 226 | task->disconnect(); 227 | 228 | /* Remove @pg from @requests */ 229 | requests.removeAll( rq ); 230 | } 231 | 232 | /* Clear the queue */ 233 | for( int q = 0; q < queue.count(); q++ ) { 234 | RenderTask *task = queuedRequests.take( q ); 235 | /* Invalidate */ 236 | task->invalidate(); 237 | 238 | /* Disconnect: Don't waste time validating it when it's complete */ 239 | task->disconnect(); 240 | 241 | /* Remove @pg from @requests */ 242 | queue.removeAll( q ); 243 | } 244 | 245 | validFrom = QDateTime::currentDateTime().toSecsSinceEpoch(); 246 | }; 247 | 248 | void PdfWidget::Renderer::validateImage( int pg, QImage img, qint64 id ) { 249 | 250 | requests.removeAll( pg ); 251 | requestCache.remove( pg ); 252 | 253 | if ( id < validFrom ) { 254 | // The document has changed. All requests made before @validFrom will be invalidated 255 | return; 256 | } 257 | 258 | /* Add @pg to @pages if it does not exist */ 259 | if ( not pages.contains( pg ) ) { 260 | /* If the cache is full, remove the oldest page */ 261 | if ( pages.count() >= pageCacheLimit ) 262 | pageCache.remove( pages.takeFirst() ); 263 | 264 | pages.append( pg ); 265 | } 266 | 267 | /* Add the @img corresponding to @pg */ 268 | pageCache.insert( pg, img ); 269 | 270 | /* Emit the signal that the page is ready */ 271 | emit pageRendered( pg ); 272 | 273 | /* Check if there are any outstanding tasks */ 274 | if ( not queue.isEmpty() ) { 275 | /* Take the first page */ 276 | int newPg = queue.takeFirst(); 277 | RenderTask *task = queuedRequests.value( newPg ); 278 | 279 | requests << newPg; 280 | requestCache.insert( newPg, task ); 281 | 282 | QThreadPool::globalInstance()->start( task ); 283 | } 284 | }; 285 | -------------------------------------------------------------------------------- /example/Gui/Widgets/Buttons/ButtonSet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ButtonSet.cpp - The Segmented Buttons Class 4 | * 5 | */ 6 | 7 | #include "ButtonSet.hpp" 8 | 9 | ButtonSet::ButtonSet() : QWidget() { 10 | 11 | myButtonHeight = 24; 12 | myButtonWidth = 100; 13 | setContentsMargins( QMargins() ); 14 | 15 | btnsLyt = new QHBoxLayout(); 16 | btnsLyt->setContentsMargins( QMargins() ); 17 | btnsLyt->setSpacing( 0 ); 18 | 19 | QWidget *btnsBase = new QWidget(); 20 | btnsBase->setObjectName( "btnsBase" ); 21 | btnsBase->setLayout( btnsLyt ); 22 | 23 | QHBoxLayout *baseLyt = new QHBoxLayout(); 24 | baseLyt->setContentsMargins( QMargins() ); 25 | baseLyt->setAlignment( Qt::AlignCenter ); 26 | baseLyt->addWidget( btnsBase ); 27 | 28 | setLayout( baseLyt ); 29 | }; 30 | 31 | ButtonSet::ButtonSet( QList icons ) : QWidget() { 32 | 33 | setContentsMargins( QMargins() ); 34 | 35 | btnsLyt = new QHBoxLayout(); 36 | btnsLyt->setContentsMargins( QMargins() ); 37 | btnsLyt->setSpacing( 0 ); 38 | 39 | segments.clear(); 40 | int max = icons.count(); 41 | for( int i = 0; i < max; i++ ) { 42 | QPushButton *btn = new QPushButton( this ); 43 | btn->setFocusPolicy( Qt::NoFocus ); 44 | btn->setFocusPolicy( Qt::NoFocus ); 45 | btn->setIcon( icons.value( i ) ); 46 | 47 | btn->setFixedHeight( myButtonHeight ); 48 | btn->setFixedWidth( myButtonWidth ); 49 | btn->setFocusPolicy( Qt::NoFocus ); 50 | 51 | connect( btn, SIGNAL( clicked() ), this, SLOT( handleSegmentClick() ) ); 52 | 53 | segments << btn; 54 | btnsLyt->addWidget( btn ); 55 | if ( i < max - 1 ) 56 | btnsLyt->addWidget( Separator::vertical() ); 57 | } 58 | 59 | QWidget *btnsBase = new QWidget(); 60 | btnsBase->setObjectName( "btnsBase" ); 61 | btnsBase->setLayout( btnsLyt ); 62 | 63 | QHBoxLayout *baseLyt = new QHBoxLayout(); 64 | baseLyt->setContentsMargins( QMargins() ); 65 | baseLyt->setAlignment( Qt::AlignCenter ); 66 | baseLyt->addWidget( btnsBase ); 67 | 68 | setLayout( baseLyt ); 69 | }; 70 | 71 | ButtonSet::ButtonSet( QStringList labels ) : QWidget() { 72 | 73 | setContentsMargins( QMargins() ); 74 | 75 | btnsLyt = new QHBoxLayout(); 76 | btnsLyt->setContentsMargins( QMargins() ); 77 | btnsLyt->setSpacing( 0 ); 78 | 79 | segments.clear(); 80 | int max = labels.count(); 81 | for( int i = 0; i < max; i++ ) { 82 | QPushButton *btn = new QPushButton( this ); 83 | btn->setFocusPolicy( Qt::NoFocus ); 84 | btn->setText( labels.value( i ) ); 85 | 86 | btn->setFixedHeight( myButtonHeight ); 87 | btn->setFixedWidth( myButtonWidth ); 88 | btn->setFocusPolicy( Qt::NoFocus ); 89 | 90 | connect( btn, SIGNAL( clicked() ), this, SLOT( handleSegmentClick() ) ); 91 | 92 | segments << btn; 93 | btnsLyt->addWidget( btn ); 94 | if ( i < max - 1 ) 95 | btnsLyt->addWidget( Separator::vertical() ); 96 | } 97 | 98 | QWidget *btnsBase = new QWidget(); 99 | btnsBase->setObjectName( "btnsBase" ); 100 | btnsBase->setLayout( btnsLyt ); 101 | 102 | QHBoxLayout *baseLyt = new QHBoxLayout(); 103 | baseLyt->setContentsMargins( QMargins() ); 104 | baseLyt->setAlignment( Qt::AlignCenter ); 105 | baseLyt->addWidget( btnsBase ); 106 | 107 | setLayout( baseLyt ); 108 | }; 109 | 110 | ButtonSet::ButtonSet( QStringList labels, QList icons ) : QWidget() { 111 | 112 | setContentsMargins( QMargins() ); 113 | 114 | btnsLyt = new QHBoxLayout(); 115 | btnsLyt->setContentsMargins( QMargins() ); 116 | btnsLyt->setSpacing( 0 ); 117 | 118 | segments.clear(); 119 | int max = qMax( labels.count(), icons.count() ); 120 | for( int i = 0; i < max; i++ ) { 121 | QPushButton *btn = new QPushButton( this ); 122 | btn->setFocusPolicy( Qt::NoFocus ); 123 | btn->setText( labels.value( i ) ); 124 | btn->setIcon( icons.value( i ) ); 125 | 126 | btn->setFixedHeight( myButtonHeight ); 127 | btn->setFixedWidth( myButtonWidth ); 128 | btn->setFocusPolicy( Qt::NoFocus ); 129 | 130 | connect( btn, SIGNAL( clicked() ), this, SLOT( handleSegmentClick() ) ); 131 | 132 | segments << btn; 133 | btnsLyt->addWidget( btn ); 134 | if ( i < max - 1 ) 135 | btnsLyt->addWidget( Separator::vertical() ); 136 | } 137 | 138 | QWidget *btnsBase = new QWidget(); 139 | btnsBase->setObjectName( "btnsBase" ); 140 | btnsBase->setLayout( btnsLyt ); 141 | 142 | QHBoxLayout *baseLyt = new QHBoxLayout(); 143 | baseLyt->setContentsMargins( QMargins() ); 144 | baseLyt->setAlignment( Qt::AlignCenter ); 145 | baseLyt->addWidget( btnsBase ); 146 | 147 | setLayout( baseLyt ); 148 | }; 149 | 150 | QPushButton* ButtonSet::segment( int sgmnt ) { 151 | 152 | return segments.at( sgmnt ); 153 | }; 154 | 155 | void ButtonSet::setSegmentIcon( int segment, QIcon segIcon ) { 156 | 157 | segments.at( segment )->setIcon( segIcon ); 158 | }; 159 | 160 | void ButtonSet::setSegmentText( int segment, QString segText ) { 161 | 162 | segments.at( segment )->setText( segText ); 163 | }; 164 | 165 | void ButtonSet::setSegmentWidth( int width ) { 166 | 167 | Q_FOREACH( QPushButton *pBtn, segments ) 168 | pBtn->setFixedWidth( width ); 169 | 170 | setFixedWidth( segments.count() * width + segments.count() * 2 ); 171 | }; 172 | 173 | void ButtonSet::setSegmentHeight( int height ) { 174 | 175 | Q_FOREACH( QPushButton *pBtn, segments ) 176 | pBtn->setFixedHeight( height ); 177 | }; 178 | 179 | void ButtonSet::setSegmentShortcut( int segment, QKeySequence shortcut ) { 180 | 181 | segments.at( segment )->setShortcut( shortcut ); 182 | }; 183 | 184 | void ButtonSet::setSegmentDisabled( int segment ) { 185 | 186 | segments.at( segment )->setDisabled( true ); 187 | }; 188 | 189 | void ButtonSet::setSegmentEnabled( int segment ) { 190 | 191 | segments.at( segment )->setEnabled( true ); 192 | }; 193 | 194 | void ButtonSet::insertSegment( QPushButton *button, int logicalPos ) { 195 | 196 | button->setFocusPolicy( Qt::NoFocus ); 197 | 198 | if ( logicalPos >= segments.count() ) { 199 | segments << button; 200 | btnsLyt->addWidget( Separator::vertical() ); 201 | btnsLyt->addWidget( button ); 202 | button->setFixedWidth( myButtonWidth ); 203 | button->setFixedHeight( myButtonHeight ); 204 | } 205 | 206 | else { 207 | connect( button, SIGNAL( clicked() ), this, SLOT( handleSegmentClick() ) ); 208 | segments.insert( logicalPos, button ); 209 | btnsLyt->insertWidget( logicalPos * 2, button ); 210 | btnsLyt->insertWidget( logicalPos * 2 + 1, Separator::vertical() ); 211 | button->setFixedWidth( myButtonWidth ); 212 | button->setFixedHeight( myButtonHeight ); 213 | } 214 | }; 215 | 216 | void ButtonSet::addSegment( QPushButton *button ) { 217 | 218 | button->setFocusPolicy( Qt::NoFocus ); 219 | 220 | if ( segments.count() ) 221 | btnsLyt->addWidget( Separator::vertical() ); 222 | 223 | btnsLyt->addWidget( button ); 224 | segments << button; 225 | button->setFixedWidth( myButtonWidth ); 226 | button->setFixedHeight( myButtonHeight ); 227 | }; 228 | 229 | void ButtonSet::handleSegmentClick() { 230 | 231 | QPushButton *btn = qobject_cast( sender() ); 232 | emit segmentClicked( segments.indexOf( btn ) ); 233 | }; 234 | 235 | // =========================== 236 | 237 | ButtonSet2::ButtonSet2() : QWidget() { 238 | 239 | myButtonHeight = 24; 240 | myButtonWidth = 24; 241 | setContentsMargins( QMargins() ); 242 | 243 | btnsLyt = new QHBoxLayout(); 244 | btnsLyt->setContentsMargins( QMargins() ); 245 | btnsLyt->setSpacing( 0 ); 246 | 247 | QWidget *btnsBase = new QWidget(); 248 | btnsBase->setObjectName( "btnsBase" ); 249 | btnsBase->setLayout( btnsLyt ); 250 | 251 | QHBoxLayout *baseLyt = new QHBoxLayout(); 252 | baseLyt->setContentsMargins( QMargins() ); 253 | baseLyt->setAlignment( Qt::AlignCenter ); 254 | baseLyt->addWidget( btnsBase ); 255 | 256 | setLayout( baseLyt ); 257 | }; 258 | 259 | ButtonSet2::ButtonSet2( QList icons ) : QWidget() { 260 | 261 | setContentsMargins( QMargins() ); 262 | 263 | btnsLyt = new QHBoxLayout(); 264 | btnsLyt->setContentsMargins( QMargins() ); 265 | btnsLyt->setSpacing( 0 ); 266 | 267 | segments.clear(); 268 | int max = icons.count(); 269 | for( int i = 0; i < max; i++ ) { 270 | QToolButton *btn = new QToolButton( this ); 271 | btn->setIcon( icons.value( i ) ); 272 | 273 | btn->setFixedHeight( myButtonHeight ); 274 | btn->setFixedWidth( myButtonWidth ); 275 | btn->setFocusPolicy( Qt::NoFocus ); 276 | 277 | connect( btn, SIGNAL( clicked() ), this, SLOT( handleSegmentClick() ) ); 278 | 279 | segments << btn; 280 | btnsLyt->addWidget( btn ); 281 | if ( i < max - 1 ) 282 | btnsLyt->addWidget( Separator::vertical() ); 283 | } 284 | 285 | QWidget *btnsBase = new QWidget(); 286 | btnsBase->setObjectName( "btnsBase" ); 287 | btnsBase->setLayout( btnsLyt ); 288 | 289 | QHBoxLayout *baseLyt = new QHBoxLayout(); 290 | baseLyt->setContentsMargins( QMargins() ); 291 | baseLyt->setAlignment( Qt::AlignCenter ); 292 | baseLyt->addWidget( btnsBase ); 293 | 294 | setLayout( baseLyt ); 295 | }; 296 | 297 | QToolButton* ButtonSet2::segment( int sgmnt ) { 298 | 299 | return segments.at( sgmnt ); 300 | }; 301 | 302 | void ButtonSet2::setSegmentIcon( int segment, QIcon segIcon ) { 303 | 304 | segments.at( segment )->setIcon( segIcon ); 305 | }; 306 | 307 | void ButtonSet2::setSegmentWidth( int width ) { 308 | 309 | Q_FOREACH( QToolButton *pBtn, segments ) 310 | pBtn->setFixedWidth( width ); 311 | 312 | setFixedWidth( segments.count() * width + segments.count() * 2 ); 313 | }; 314 | 315 | void ButtonSet2::setSegmentHeight( int height ) { 316 | 317 | Q_FOREACH( QToolButton *pBtn, segments ) 318 | pBtn->setFixedHeight( height ); 319 | }; 320 | 321 | void ButtonSet2::setSegmentShortcut( int segment, QKeySequence shortcut ) { 322 | 323 | segments.at( segment )->setShortcut( shortcut ); 324 | }; 325 | 326 | void ButtonSet2::setSegmentDisabled( int segment ) { 327 | 328 | segments.at( segment )->setDisabled( true ); 329 | }; 330 | 331 | void ButtonSet2::setSegmentEnabled( int segment ) { 332 | 333 | segments.at( segment )->setEnabled( true ); 334 | }; 335 | 336 | void ButtonSet2::insertSegment( QToolButton *button, int logicalPos ) { 337 | 338 | if ( logicalPos >= segments.count() ) { 339 | segments << button; 340 | btnsLyt->addWidget( Separator::vertical() ); 341 | btnsLyt->addWidget( button ); 342 | button->setFixedWidth( myButtonWidth ); 343 | button->setFixedHeight( myButtonHeight ); 344 | } 345 | 346 | else { 347 | connect( button, SIGNAL( clicked() ), this, SLOT( handleSegmentClick() ) ); 348 | segments.insert( logicalPos, button ); 349 | btnsLyt->insertWidget( logicalPos * 2, button ); 350 | btnsLyt->insertWidget( logicalPos * 2 + 1, Separator::vertical() ); 351 | button->setFixedWidth( myButtonWidth ); 352 | button->setFixedHeight( myButtonHeight ); 353 | } 354 | }; 355 | 356 | void ButtonSet2::addSegment( QToolButton *button ) { 357 | 358 | if ( segments.count() ) 359 | btnsLyt->addWidget( Separator::vertical() ); 360 | 361 | btnsLyt->addWidget( button ); 362 | segments << button; 363 | button->setFixedWidth( myButtonWidth ); 364 | button->setFixedHeight( myButtonHeight ); 365 | }; 366 | 367 | void ButtonSet2::handleSegmentClick() { 368 | 369 | QToolButton *btn = qobject_cast( sender() ); 370 | emit segmentClicked( segments.indexOf( btn ) ); 371 | }; 372 | -------------------------------------------------------------------------------- /example/Gui/Application/MPApplication.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright ( C ) 2010 Nokia Corporation and/or its subsidiary( -ies ). 4 | ** All rights reserved. 5 | ** 6 | ** Contact: Nokia Corporation ( qt-info@nokia.com ) 7 | ** 8 | ** This file is part of a Qt Solutions component. 9 | ** 10 | ** You may use this file under the terms of the BSD license as follows: 11 | ** 12 | ** "Redistribution and use in source and binary forms, with or without 13 | ** modification, are permitted provided that the following conditions are 14 | ** met: 15 | ** * Redistributions of source code must retain the above copyright 16 | ** notice, this list of conditions and the following disclaimer. 17 | ** * Redistributions in binary form must reproduce the above copyright 18 | ** notice, this list of conditions and the following disclaimer in 19 | ** the documentation and/or other materials provided with the 20 | ** distribution. 21 | ** * Neither the name of Nokia Corporation and its Subsidiary( -ies ) nor 22 | ** the names of its contributors may be used to endorse or promote 23 | ** products derived from this software without specific prior written 24 | ** permission. 25 | ** 26 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT 32 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY 34 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | ** ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE 36 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 37 | ** 38 | ****************************************************************************/ 39 | 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | 46 | /*! 47 | \class MPApplication MPApplication.h 48 | \brief The MPApplication class provides an API to detect and 49 | communicate with running instances of an application. 50 | 51 | This class allows you to create applications where only one 52 | instance should be running at a time. I.e., if the user tries to 53 | launch another instance, the already running instance will be 54 | activated instead. Another usecase is a client-server system, 55 | where the first started instance will assume the role of server, 56 | and the later instances will act as clients of that server. 57 | 58 | By default, the full path of the executable file is used to 59 | determine whether two processes are instances of the same 60 | application. You can also provide an explicit identifier string 61 | that will be compared instead. 62 | 63 | The application should create the MPApplication object early 64 | in the startup phase, and call isRunning() to find out if another 65 | instance of this application is already running. If isRunning() 66 | returns false, it means that no other instance is running, and 67 | this instance has assumed the role as the running instance. In 68 | this case, the application should continue with the initialization 69 | of the application user interface before entering the event loop 70 | with exec(), as normal. 71 | 72 | The messageReceived() signal will be emitted when the running 73 | application receives messages from another instance of the same 74 | application. When a message is received it might be helpful to the 75 | user to raise the application so that it becomes visible. To 76 | facilitate this, MPApplication provides the 77 | setActivationWindow() function and the activateWindow() slot. 78 | 79 | If isRunning() returns true, another instance is already 80 | running. It may be alerted to the fact that another instance has 81 | started by using the sendMessage() function. Also data such as 82 | startup parameters ( e.g. the name of the file the user wanted this 83 | new instance to open ) can be passed to the running instance with 84 | this function. Then, the application should terminate ( or enter 85 | client mode ). 86 | 87 | If isRunning() returns true, but sendMessage() fails, that is an 88 | indication that the running instance is frozen. 89 | 90 | Here's an example that shows how to convert an existing 91 | application to use MPApplication. It is very simple and does 92 | not make use of all MPApplication's functionality ( see the 93 | examples for that ). 94 | 95 | \code 96 | // Original 97 | int main( int argc, char **argv ) 98 | { 99 | QApplication app( argc, argv ); 100 | 101 | MyMainWidget mmw; 102 | mmw.show(); 103 | return app.exec(); 104 | } 105 | 106 | // Single instance 107 | int main( int argc, char **argv ) 108 | { 109 | MPApplication app( argc, argv ); 110 | 111 | if ( app.isRunning() ) 112 | return !app.sendMessage( someDataString ); 113 | 114 | MyMainWidget mmw; 115 | app.setActivationWindow( &mmw ); 116 | mmw.show(); 117 | return app.exec(); 118 | } 119 | \endcode 120 | 121 | Once this MPApplication instance is destroyed ( normally when 122 | the process exits or crashes ), when the user next attempts to run the 123 | application this instance will not, of course, be encountered. The 124 | next instance to call isRunning() or sendMessage() will assume the 125 | role as the new running instance. 126 | 127 | For console ( non-GUI ) applications, QtSingleCoreApplication may be 128 | used instead of this class, to avoid the dependency on the QtGui 129 | library. 130 | 131 | \sa QtSingleCoreApplication 132 | */ 133 | 134 | 135 | void MPApplication::sysInit( const QString &appId ) { 136 | 137 | actWin = 0; 138 | peer = new QtLocalPeer( this, appId ); 139 | connect( peer, SIGNAL( messageReceived( const QString& ) ), SIGNAL( messageReceived( const QString& ) ) ); 140 | } 141 | 142 | 143 | /*! 144 | Creates a MPApplication object. The application identifier 145 | will be QCoreApplication::applicationFilePath(). \a argc, \a 146 | argv, and \a GUIenabled are passed on to the QAppliation constructor. 147 | 148 | If you are creating a console application ( i.e. setting \a 149 | GUIenabled to false ), you may consider using 150 | QtSingleCoreApplication instead. 151 | */ 152 | 153 | MPApplication::MPApplication( int &argc, char **argv, bool GUIenabled ) : QApplication( argc, argv, GUIenabled ) { 154 | 155 | sysInit(); 156 | } 157 | 158 | 159 | /*! 160 | Creates a MPApplication object with the application 161 | identifier \a appId. \a argc and \a argv are passed on to the 162 | QAppliation constructor. 163 | */ 164 | 165 | MPApplication::MPApplication( const QString &appId, int &argc, char **argv ) : QApplication( argc, argv ) { 166 | 167 | sysInit( appId ); 168 | } 169 | 170 | 171 | /*! 172 | Returns true if another instance of this application is running; 173 | otherwise false. 174 | 175 | This function does not find instances of this application that are 176 | being run by a different user ( on Windows: that are running in 177 | another session ). 178 | 179 | \sa sendMessage() 180 | */ 181 | 182 | bool MPApplication::isRunning() { 183 | 184 | return peer->isClient(); 185 | } 186 | 187 | 188 | /*! 189 | Tries to send the text \a message to the currently running 190 | instance. The MPApplication object in the running instance 191 | will emit the messageReceived() signal when it receives the 192 | message. 193 | 194 | This function returns true if the message has been sent to, and 195 | processed by, the current instance. If there is no instance 196 | currently running, or if the running instance fails to process the 197 | message within \a timeout milliseconds, this function return false. 198 | 199 | \sa isRunning(), messageReceived() 200 | */ 201 | bool MPApplication::sendMessage( const QString &message, int timeout ) { 202 | 203 | return peer->sendMessage( message, timeout ); 204 | } 205 | 206 | 207 | /*! 208 | Returns the application identifier. Two processes with the same 209 | identifier will be regarded as instances of the same application. 210 | */ 211 | QString MPApplication::id() const { 212 | 213 | return peer->applicationId(); 214 | } 215 | 216 | 217 | /*! 218 | Sets the activation window of this application to \a aw. The 219 | activation window is the widget that will be activated by 220 | activateWindow(). This is typically the application's main window. 221 | 222 | If \a activateOnMessage is true ( the default ), the window will be 223 | activated automatically every time a message is received, just prior 224 | to the messageReceived() signal being emitted. 225 | 226 | \sa activateWindow(), messageReceived() 227 | */ 228 | 229 | void MPApplication::setActivationWindow( QWidget* aw, bool activateOnMessage ) { 230 | 231 | actWin = aw; 232 | if ( activateOnMessage ) 233 | QObject::connect( peer, SIGNAL( messageReceived( const QString& ) ), this, SLOT( activateWindow() ) ); 234 | 235 | else 236 | QObject::disconnect( peer, SIGNAL( messageReceived( const QString& ) ), this, SLOT( activateWindow() ) ); 237 | } 238 | 239 | 240 | /*! 241 | Returns the applications activation window if one has been set by 242 | calling setActivationWindow(), otherwise returns 0. 243 | 244 | \sa setActivationWindow() 245 | */ 246 | QWidget* MPApplication::activationWindow() const { 247 | 248 | return actWin; 249 | } 250 | 251 | 252 | /*! 253 | De-minimizes, raises, and activates this application's activation window. 254 | This function does nothing if no activation window has been set. 255 | 256 | This is a convenience function to show the user that this 257 | application instance has been activated when he has tried to start 258 | another instance. 259 | 260 | This function should typically be called in response to the 261 | messageReceived() signal. By default, that will happen 262 | automatically, if an activation window has been set. 263 | 264 | \sa setActivationWindow(), messageReceived(), initialize() 265 | */ 266 | void MPApplication::activateWindow() { 267 | 268 | if ( actWin ) { 269 | actWin->setWindowState( actWin->windowState() & ~Qt::WindowMinimized ); 270 | actWin->raise(); 271 | actWin->activateWindow(); 272 | } 273 | } 274 | 275 | void MPApplication::disconnect() { 276 | 277 | peer->shutdown(); 278 | } 279 | 280 | 281 | /*! 282 | \fn void MPApplication::messageReceived( const QString& message ) 283 | 284 | This signal is emitted when the current instance receives a \a 285 | message from another instance of this application. 286 | 287 | \sa sendMessage(), setActivationWindow(), activateWindow() 288 | */ 289 | 290 | 291 | /*! 292 | \fn void MPApplication::initialize( bool dummy = true ) 293 | 294 | \obsolete 295 | */ 296 | -------------------------------------------------------------------------------- /example/Gui/Dialogs/MessageDialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * MessageDialog.cpp - MessageDialog class 4 | * 5 | */ 6 | 7 | #include "MessageDialog.hpp" 8 | 9 | MessageDialog::MessageDialog( QWidget *parent, QString icon, QString title, QString text, QList btns, QWidget *info ) : Dialog( parent ) { 10 | 11 | setDialogIcon( QIcon( ":/icons/minipdf.png" ) ); 12 | 13 | QVBoxLayout *dlgLyt = new QVBoxLayout(); 14 | dlgLyt->setContentsMargins( QMargins() ); 15 | 16 | QHBoxLayout *msgLyt = new QHBoxLayout(); 17 | QHBoxLayout *btnLyt = new QHBoxLayout(); 18 | 19 | iconLbl = new QLabel(); 20 | iconLbl->setMaximumSize( QSize( 64, 64 ) ); 21 | iconLbl->setPixmap( QPixmap( icon ).scaled( 64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); 22 | 23 | textLbl = new QLabel( text ); 24 | textLbl->setWordWrap( true ); 25 | 26 | setTitle( title ); 27 | 28 | msgLyt->addWidget( iconLbl ); 29 | msgLyt->addWidget( textLbl ); 30 | 31 | if ( btns.count() == 0 ) 32 | btns << MessageDialog::Ok; 33 | 34 | if ( info ) { 35 | infoWidget = qobject_cast( info ); 36 | infoWidget->hide(); 37 | 38 | detailsBtn = new QPushButton( QIcon( ":/icons/info.png" ), "&More" ); 39 | connect( detailsBtn, SIGNAL( clicked() ), this, SLOT( toggleInfoWidget() ) ); 40 | btnLyt->addWidget( detailsBtn ); 41 | } 42 | 43 | btnLyt->addStretch( 0 ); 44 | 45 | ButtonSet *bSet = new ButtonSet(); 46 | 47 | QStringList labels; 48 | QList icons; 49 | 50 | foreach( StandardButton btn, btns ) { 51 | QPushButton *button; 52 | switch( btn ) { 53 | case MessageDialog::Ok : 54 | button = new QPushButton( QIcon( ":/icons/ok.png" ), "&Ok" ); 55 | button->setObjectName( tr( "okBtn" ) ); 56 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 57 | bSet->addSegment( button ); 58 | break; 59 | 60 | case MessageDialog::Yes : 61 | button = new QPushButton( QIcon( ":/icons/ok.png" ), "&Yes" ); 62 | button->setObjectName( tr( "okBtn" ) ); 63 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 64 | bSet->addSegment( button ); 65 | break; 66 | 67 | case MessageDialog::YesToAll : 68 | button = new QPushButton( QIcon( ":/icons/ok.png" ), "Yes to &All" ); 69 | button->setObjectName( tr( "okBtn" ) ); 70 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 71 | bSet->addSegment( button ); 72 | break; 73 | 74 | case MessageDialog::No : 75 | button = new QPushButton( QIcon( ":/icons/delete2.png" ), "&No" ); 76 | button->setObjectName( tr( "cancelBtn" ) ); 77 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 78 | bSet->addSegment( button ); 79 | break; 80 | 81 | case MessageDialog::NoToAll : 82 | button = new QPushButton( QIcon( ":/icons/delete2.png" ), "N&o to All" ); 83 | button->setObjectName( tr( "cancelBtn" ) ); 84 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 85 | bSet->addSegment( button ); 86 | break; 87 | 88 | case MessageDialog::Abort : 89 | button = new QPushButton( QIcon( ":/icons/abort.png" ), "A&bort" ); 90 | button->setObjectName( tr( "abortBtn" ) ); 91 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 92 | bSet->addSegment( button ); 93 | break; 94 | 95 | case MessageDialog::Retry : 96 | button = new QPushButton( QIcon( ":/icons/refresh.png" ), "&Retry" ); 97 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 98 | bSet->addSegment( button ); 99 | break; 100 | 101 | case MessageDialog::Ignore : 102 | button = new QPushButton( QIcon( ":/icons/ok.png" ), "&Ignore" ); 103 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 104 | bSet->addSegment( button ); 105 | break; 106 | 107 | case MessageDialog::Cancel : 108 | button = new QPushButton( QIcon::fromTheme( "dialog-cancel" ), "&Cancel" ); 109 | button->setObjectName( tr( "cancelBtn" ) ); 110 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 111 | bSet->addSegment( button ); 112 | break; 113 | 114 | case MessageDialog::Save : 115 | button = new QPushButton( QIcon::fromTheme( "document-save" ), "&Save" ); 116 | button->setObjectName( tr( "okBtn" ) ); 117 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 118 | bSet->addSegment( button ); 119 | break; 120 | 121 | case MessageDialog::Discard : 122 | button = new QPushButton( QIcon::fromTheme( "document-close" ), "&Discard" ); 123 | button->setObjectName( tr( "abortBtn" ) ); 124 | connect( button, SIGNAL( clicked() ), this, SLOT( buttonClickHandler() ) ); 125 | bSet->addSegment( button ); 126 | break; 127 | 128 | default: 129 | qDebug() << "No Button added!!"; 130 | break; 131 | } 132 | } 133 | 134 | bSet->setSegmentWidth( 100 ); 135 | bSet->setSegmentHeight( 24 ); 136 | btnLyt->addWidget( bSet ); 137 | 138 | dlgLyt->addLayout( msgLyt ); 139 | if ( info ) 140 | dlgLyt->addWidget( infoWidget ); 141 | 142 | dlgLyt->addWidget( Separator::horizontal() ); 143 | dlgLyt->addLayout( btnLyt ); 144 | 145 | Dialog::setLayout( dlgLyt ); 146 | }; 147 | 148 | void MessageDialog::setIcon( QString icon ) { 149 | 150 | iconLbl->setPixmap( QPixmap( icon ).scaled( 64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); 151 | }; 152 | 153 | void MessageDialog::setTitle( QString title ) { 154 | 155 | Dialog::setDialogTitle( title ); 156 | }; 157 | 158 | void MessageDialog::setText( QString text ) { 159 | 160 | textLbl->setText( text ); 161 | }; 162 | 163 | void MessageDialog::keyPressEvent( QKeyEvent *keyEvent ) { 164 | 165 | if ( keyEvent->key() == Qt::Key_Escape ) { 166 | retValue = MessageDialog::Cancel; 167 | close(); 168 | } 169 | 170 | Dialog::keyPressEvent( keyEvent ); 171 | }; 172 | 173 | void MessageDialog::close() { 174 | 175 | Dialog::close(); 176 | emit closed(); 177 | }; 178 | 179 | void MessageDialog::toggleInfoWidget() { 180 | 181 | if ( infoWidget->isVisible() ) { 182 | detailsBtn->setText( "&More..." ); 183 | infoWidget->hide(); 184 | 185 | restoreGeometry( origGeometry ); 186 | } 187 | 188 | else { 189 | origGeometry = saveGeometry(); 190 | 191 | detailsBtn->setText( "&Less..." ); 192 | infoWidget->show(); 193 | 194 | adjustSize(); 195 | } 196 | }; 197 | 198 | void MessageDialog::buttonClickHandler() { 199 | 200 | QString text = qobject_cast( sender() )->text(); 201 | 202 | if ( text == QString( "&Ok" ) ) { 203 | retValue = MessageDialog::Ok; 204 | close(); 205 | } 206 | 207 | else if ( text == QString( "&Yes" ) ) { 208 | retValue = MessageDialog::Yes; 209 | close(); 210 | } 211 | 212 | else if ( text == QString( "Yes to &All" ) ) { 213 | retValue = MessageDialog::YesToAll; 214 | close(); 215 | } 216 | 217 | else if ( text == QString( "&No" ) ) { 218 | retValue = MessageDialog::No; 219 | close(); 220 | } 221 | 222 | else if ( text == QString( "N&o to All" ) ) { 223 | retValue = MessageDialog::NoToAll; 224 | close(); 225 | } 226 | 227 | else if ( text == QString( "A&bort" ) ) { 228 | retValue = MessageDialog::Abort; 229 | close(); 230 | } 231 | 232 | else if ( text == QString( "&Retry" ) ) { 233 | retValue = MessageDialog::Retry; 234 | close(); 235 | } 236 | 237 | else if ( text == QString( "&Ignore" ) ) { 238 | retValue = MessageDialog::Ignore; 239 | close(); 240 | } 241 | 242 | else if ( text == QString( "&Cancel" ) ) { 243 | retValue = MessageDialog::Cancel; 244 | close(); 245 | } 246 | 247 | else if ( text == QString( "&Save" ) ) { 248 | retValue = MessageDialog::Save; 249 | close(); 250 | } 251 | 252 | else if ( text == QString( "&Discard" ) ) { 253 | retValue = MessageDialog::Discard; 254 | close(); 255 | } 256 | }; 257 | 258 | void MessageDialog::aboutNewBreeze() { 259 | 260 | QString title = QString( "About NewBreeze v2.5.0" ); 261 | QString text = QString( 262 | "

Fast and light-weight File Manager

" \ 263 | "

Built on top of the Powerful Qt4 GUI Toolkit, this file manager " \ 264 | "is sleek, stylish and fast. Some of its features are

" \ 265 | "
    " \ 266 | "
  • Fast startup and browsing
  • " \ 267 | "
  • Folder, text, html, image and odt quick preview
  • " \ 268 | "
  • File Association support
  • " \ 269 | "
  • Multiple Views - Tiles, Icons and Details
  • " \ 270 | "
  • Sleek side panel showing drives and boomarks
  • " \ 271 | "
  • Full drag and drop support
  • " \ 272 | "
  • Applications and Catalog View
  • " \ 273 | "
  • Custom Folder Icons and Thumbnail Preview
  • " \ 274 | "
  • Mime-Icon Support
  • " \ 275 | "
  • BreadCrumbs Navigation
  • " \ 276 | "
  • Custom Actions
  • " \ 277 | "
  • Inline terminal
  • " \ 278 | "
" \ 279 | "

The credit for the inline terminal goes to " \ 280 | "Christian Surlykke, the author of QTermWidget. " \ 281 | "I have used the QTermWidget to dispaly the " \ 282 | "inline terminal.

" \ 283 | ); 284 | QList btns = QList() << MessageDialog::Ok; 285 | 286 | MessageDialog *dlg = new MessageDialog( 0, ":/icons/newbreeze2.png", title, text, btns ); 287 | dlg->setFixedSize( 540, 390 ); 288 | dlg->exec(); 289 | }; 290 | 291 | void MessageDialog::aboutQt() { 292 | 293 | QString title = QObject::tr( 294 | "About Qt %1" 295 | ).arg( QLatin1String( QT_VERSION_STR ) ); 296 | 297 | QString text = QObject::tr( 298 | "

Qt is a C++ toolkit for cross-platform application development.

" 299 | 300 | "

Qt provides single-source portability across MS Windows, Mac OS X, Linux, and all major commercial Unix" 301 | "variants. Qt is also available for embedded devices as Qt for Embedded Linux and Qt for Windows CE.

" 302 | 303 | "

Qt is available under three different licensing options designed to accommodate the needs of our various users.

" 304 | 305 | "

Qt licensed under our commercial license agreement is appropriate for development of proprietary/commercial software where you do " 306 | "not want to share any source code with third parties or otherwise cannot comply with the terms of the GNU LGPL version 2.1 or GNU " 307 | "GPL version 3.0.

" 308 | 309 | "

Qt licensed under the GNU LGPL version 2.1 is appropriate for the development of Qt applications (proprietary or open source) " 310 | "provided you can comply with the terms and conditions of the GNU LGPL version 2.1.

" 311 | 312 | "

Qt licensed under the GNU General Public License version 3.0 is appropriate for the development of Qt applications where you wish " 313 | "to use such applications in combination with software subject to the terms of the GNU GPL version 3.0 or where you are otherwise " 314 | "willing to comply with the terms of the GNU GPL version 3.0.

" 315 | 316 | "

Please see qt.digia.com/product/licensing for an overview of Qt licensing.

" 317 | 318 | "

Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).

" 319 | 320 | "

Qt is a Digia product. See qt.digia.com for more information.

" 321 | ); 322 | 323 | QList btns = QList() << MessageDialog::Ok; 324 | 325 | MessageDialog *dlg = new MessageDialog( NULL, ":/icons/QtLogo.png", title, text, btns ); 326 | dlg->setMinimumSize( 630, 450 ); 327 | dlg->exec(); 328 | }; 329 | 330 | int MessageDialog::information( QWidget* parent, QString title, QString text, QList btns, QWidget *infoWidget ) { 331 | 332 | MessageDialog *dlg = new MessageDialog( parent, ":/icons/info.png", title, text, btns, infoWidget ); 333 | dlg->exec(); 334 | 335 | return dlg->retValue; 336 | }; 337 | 338 | int MessageDialog::question( QWidget* parent, QString title, QString text, QList btns, QWidget *infoWidget ) { 339 | 340 | MessageDialog *dlg = new MessageDialog( parent, ":/icons/question.png", title, text, btns, infoWidget ); 341 | dlg->exec(); 342 | 343 | return dlg->retValue; 344 | }; 345 | 346 | int MessageDialog::warning( QWidget* parent, QString title, QString text, QList btns, QWidget *infoWidget ) { 347 | 348 | MessageDialog *dlg = new MessageDialog( parent, ":/icons/warning.png", title, text, btns, infoWidget ); 349 | dlg->exec(); 350 | 351 | return dlg->retValue; 352 | }; 353 | 354 | int MessageDialog::error( QWidget* parent, QString title, QString text, QList btns, QWidget *infoWidget ) { 355 | 356 | MessageDialog *dlg = new MessageDialog( parent, ":/icons/error.png", title, text, btns, infoWidget ); 357 | dlg->exec(); 358 | 359 | return dlg->retValue; 360 | }; 361 | 362 | int MessageDialog::critical( QWidget* parent, QString title, QString text, QList btns, QWidget *infoWidget ) { 363 | 364 | MessageDialog *dlg = new MessageDialog( parent, ":/icons/stop.png", title, text, btns, infoWidget ); 365 | dlg->exec(); 366 | 367 | return dlg->retValue; 368 | }; 369 | -------------------------------------------------------------------------------- /lib/MuPdf/MuPdfDocument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is a part of PdfWidget. 4 | * PdfWidget is the default document viewer for the DesQ Suite 5 | * Copyright 2019-2021 Britanicus 6 | * 7 | 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * at your option, any later version. 13 | * 14 | 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 26 | * MA 02110-1301, USA. 27 | * 28 | */ 29 | 30 | #include "MuPdfDocument.hpp" 31 | 32 | MuPdfDocument::MuPdfDocument( QString pdfPath ) : PdfWidget::Document( pdfPath ) { 33 | 34 | mCtx = nullptr; 35 | mFzDoc = nullptr; 36 | }; 37 | 38 | void MuPdfDocument::setPassword( QString password ) { 39 | 40 | if ( not fz_authenticate_password( mCtx, mFzDoc, password.toUtf8().constData() ) ) { 41 | fprintf( stderr, "Invalid password. Please try again.\n" ); 42 | mPassNeeded = true; 43 | emit statusChanged( Error ); 44 | 45 | return; 46 | } 47 | 48 | for( int i = 0; i < mPageCount; i++ ) { 49 | fz_page *pg; 50 | 51 | fz_try( mCtx ) { 52 | 53 | pg = fz_load_page( mCtx, mFzDoc, i ); 54 | } 55 | 56 | fz_catch( mCtx ) { 57 | fprintf( stderr, "Cannot create page: %s\n", fz_caught_message( mCtx ) ); 58 | 59 | fz_drop_document( mCtx, mFzDoc ); 60 | fz_drop_page( mCtx, pg ); 61 | fz_drop_context( mCtx ); 62 | 63 | emit statusChanged( Error ); 64 | return; 65 | } 66 | 67 | /** Create MuPage isntance */ 68 | MuPage *page = new MuPage( mCtx, pg, i ); 69 | mPages << page; 70 | 71 | /** Drop reference to pg */ 72 | fz_drop_page( mCtx, pg ); 73 | 74 | emit loading( 1.0 * i / mPageCount * 100.0 ); 75 | } 76 | 77 | mStatus = Ready; 78 | mDocError = NoError; 79 | 80 | emit statusChanged( Ready ); 81 | emit pageCountChanged( mPages.count() ); 82 | emit loading( 100 ); 83 | }; 84 | 85 | QString MuPdfDocument::title() const { 86 | 87 | char buf[1024] = { 0 }; 88 | fz_lookup_metadata( mCtx, mFzDoc, "info:Title", buf, 1024 ); 89 | 90 | return buf; 91 | }; 92 | 93 | QString MuPdfDocument::author() const { 94 | 95 | char buf[1024] = { 0 }; 96 | fz_lookup_metadata( mCtx, mFzDoc, "info:Author", buf, 1024 ); 97 | 98 | return buf; 99 | }; 100 | 101 | QString MuPdfDocument::creator() const { 102 | 103 | char buf[1024] = { 0 }; 104 | fz_lookup_metadata( mCtx, mFzDoc, "info:Creator", buf, 1024 ); 105 | 106 | return buf; 107 | }; 108 | 109 | QString MuPdfDocument::producer() const { 110 | 111 | char buf[1024] = { 0 }; 112 | fz_lookup_metadata( mCtx, mFzDoc, "info:Producer", buf, 1024 ); 113 | 114 | return buf; 115 | }; 116 | 117 | QString MuPdfDocument::created() const { 118 | 119 | char buf[1024] = { 0 }; 120 | fz_lookup_metadata( mCtx, mFzDoc, "info:CreationDate", buf, 1024 ); 121 | 122 | return buf; 123 | }; 124 | 125 | void MuPdfDocument::load() { 126 | 127 | /** Create context */ 128 | mCtx = fz_new_context( NULL, NULL, FZ_STORE_UNLIMITED ); 129 | if ( not mCtx ) { 130 | fprintf( stderr, "Cannot create mupdf context\n" ); 131 | emit statusChanged( Error ); 132 | return; 133 | } 134 | 135 | /** Register the default file types to handle. */ 136 | fz_try( mCtx ){ 137 | 138 | fz_register_document_handlers( mCtx ); 139 | } 140 | 141 | fz_catch( mCtx ) { 142 | 143 | fprintf( stderr, "Cannot register document handlers: %s\n", fz_caught_message( mCtx ) ) ; 144 | 145 | fz_drop_context( mCtx ); 146 | 147 | emit statusChanged( Error ); 148 | return; 149 | } 150 | 151 | /** Open the document. */ 152 | fz_try( mCtx ) { 153 | mFzDoc = fz_open_document( mCtx, mDocPath.toUtf8().constData() ); 154 | } 155 | 156 | fz_catch( mCtx ) { 157 | 158 | fprintf( stderr, "Cannot open document: %s\n", fz_caught_message( mCtx ) ); 159 | 160 | fz_drop_context( mCtx ); 161 | 162 | emit statusChanged( Error ); 163 | return; 164 | } 165 | 166 | /** Count the number of pages. */ 167 | fz_try( mCtx ) { 168 | mPageCount = fz_count_pages( mCtx, mFzDoc ); 169 | } 170 | 171 | fz_catch( mCtx ) { 172 | 173 | fprintf( stderr, "Cannot count number of pages: %s\n", fz_caught_message( mCtx ) ); 174 | 175 | fz_drop_document( mCtx, mFzDoc ); 176 | fz_drop_context( mCtx ); 177 | 178 | emit statusChanged( Error ); 179 | return; 180 | } 181 | 182 | /** Check if the document is encrypted */ 183 | if ( fz_needs_password( mCtx, mFzDoc ) ) { 184 | fprintf( stderr, "Cannot load encrypted document\n" ); 185 | 186 | fz_drop_document( mCtx, mFzDoc ); 187 | fz_drop_context( mCtx ); 188 | 189 | mStatus = Error; 190 | mDocError = IncorrectPasswordError; 191 | mPassNeeded = true; 192 | 193 | emit passwordRequired(); 194 | emit statusChanged( Error ); 195 | 196 | return; 197 | } 198 | 199 | for( int i = 0; i < mPageCount; i++ ) { 200 | fz_page *pg; 201 | 202 | fz_try( mCtx ) { 203 | 204 | pg = fz_load_page( mCtx, mFzDoc, i ); 205 | } 206 | 207 | fz_catch( mCtx ) { 208 | fprintf( stderr, "Cannot create page: %s\n", fz_caught_message( mCtx ) ); 209 | 210 | fz_drop_document( mCtx, mFzDoc ); 211 | fz_drop_page( mCtx, pg ); 212 | fz_drop_context( mCtx ); 213 | 214 | emit statusChanged( Error ); 215 | return; 216 | } 217 | 218 | /** Create MuPage isntance */ 219 | MuPage *page = new MuPage( mCtx, pg, i ); 220 | mPages << page; 221 | 222 | /** Drop reference to pg */ 223 | fz_drop_page( mCtx, pg ); 224 | 225 | emit loading( 1.0 * i / mPageCount * 100.0 ); 226 | } 227 | 228 | mStatus = Ready; 229 | mDocError = NoError; 230 | 231 | emit statusChanged( Ready ); 232 | emit pageCountChanged( mPages.count() ); 233 | emit loading( 100 ); 234 | }; 235 | 236 | void MuPdfDocument::close() { 237 | 238 | mStatus = Unloading; 239 | mPages.clear(); 240 | mZoom = 1.0; 241 | 242 | fz_drop_document( mCtx, mFzDoc ); 243 | fz_drop_context( mCtx ); 244 | }; 245 | 246 | 247 | MuPage::MuPage( fz_context *ctx, fz_page *pg, int pgNo ) : Page( pgNo ) { 248 | 249 | mCtx = ctx; 250 | mPage = fz_keep_page( ctx, pg ); 251 | }; 252 | 253 | MuPage::~MuPage() { 254 | 255 | fz_drop_page( mCtx, mPage ); 256 | fz_drop_context( mCtx ); 257 | }; 258 | 259 | QSizeF MuPage::pageSize( qreal zoom ) const { 260 | 261 | fz_rect pgBox = fz_bound_page( mCtx, mPage ); 262 | return QSizeF( pgBox.x1 - pgBox.x0, pgBox.y1 - pgBox.y0 ) * zoom; 263 | }; 264 | 265 | QImage MuPage::thumbnail() const { 266 | 267 | // return mPage->thumbnail(); 268 | return QImage(); 269 | }; 270 | 271 | QImage MuPage::render( QSize pSize, PdfWidget::RenderOptions opts ) const { 272 | 273 | qreal wZoom = 1.0 * pSize.width() / pageSize().width(); 274 | qreal hZoom = 1.0 * pSize.height() / pageSize().height(); 275 | 276 | fz_irect iBox; 277 | fz_rect rBox; 278 | fz_pixmap *image; 279 | fz_colorspace *colorspace; 280 | fz_matrix mMtx; 281 | 282 | colorspace = fz_device_bgr( mCtx ); 283 | 284 | /** Otherwise, the page renders incorrectly */ 285 | qreal rwZoom = pow( wZoom, 0.5 ); 286 | qreal rhZoom = pow( hZoom, 0.5 ); 287 | 288 | /** Setup the rotation */ 289 | switch( ( PdfWidget::RenderOptions::Rotation )opts.rotation() ) { 290 | case PdfWidget::RenderOptions::Rotate0: 291 | mMtx = fz_rotate( 0 ); 292 | break; 293 | 294 | case PdfWidget::RenderOptions::Rotate90: 295 | mMtx = fz_rotate( 90 ); 296 | break; 297 | 298 | case PdfWidget::RenderOptions::Rotate180: 299 | mMtx = fz_rotate( 180 ); 300 | break; 301 | 302 | case PdfWidget::RenderOptions::Rotate270: 303 | mMtx = fz_rotate( 270 ); 304 | break; 305 | } 306 | 307 | mMtx = fz_scale( rwZoom, rhZoom ); 308 | 309 | rBox = fz_bound_page( mCtx, mPage ); 310 | iBox = fz_round_rect( fz_transform_rect( rBox, mMtx ) ); 311 | rBox = fz_rect_from_irect( iBox ); 312 | 313 | /** Necessary: otherwise only a part of the page is rendered */ 314 | iBox.x1 *= rwZoom; 315 | iBox.y1 *= rhZoom; 316 | 317 | fz_try( mCtx ) { 318 | image = fz_new_pixmap_with_bbox( mCtx, colorspace, iBox, 0, 1 ); 319 | fz_clear_pixmap_with_value( mCtx, image, 0xff ); 320 | fz_device *dev = fz_new_draw_device_with_bbox( mCtx, mMtx, image, &iBox ); 321 | 322 | fz_run_page( mCtx, mPage, dev, mMtx, NULL ); 323 | } 324 | 325 | fz_catch( mCtx ) { 326 | 327 | fprintf( stderr, "Cannot render page: %s\n", fz_caught_message( mCtx ) ) ; 328 | fz_drop_page( mCtx, mPage ); 329 | fz_drop_colorspace( mCtx, colorspace ); 330 | return QImage(); 331 | } 332 | 333 | QImage img = QImage( image->samples, ( iBox.x1 - iBox.x0 ), ( iBox.y1 - iBox.y0 ), QImage::Format_ARGB32 ); 334 | 335 | return img; 336 | }; 337 | 338 | QImage MuPage::render( qreal zoomFactor, PdfWidget::RenderOptions opts ) const { 339 | 340 | fz_irect iBox; 341 | fz_rect rBox; 342 | fz_pixmap *image; 343 | fz_colorspace *colorspace; 344 | fz_matrix mMtx; 345 | 346 | colorspace = fz_device_bgr( mCtx ); 347 | 348 | /** Otherwise, the page renders incorrectly */ 349 | qreal rwZoom = pow( zoomFactor, 0.5 ); 350 | qreal rhZoom = pow( zoomFactor, 0.5 ); 351 | 352 | /** Setup the rotation */ 353 | switch( ( PdfWidget::RenderOptions::Rotation )opts.rotation() ) { 354 | case PdfWidget::RenderOptions::Rotate0: 355 | mMtx = fz_rotate( 0 ); 356 | break; 357 | 358 | case PdfWidget::RenderOptions::Rotate90: 359 | mMtx = fz_rotate( 90 ); 360 | break; 361 | 362 | case PdfWidget::RenderOptions::Rotate180: 363 | mMtx = fz_rotate( 180 ); 364 | break; 365 | 366 | case PdfWidget::RenderOptions::Rotate270: 367 | mMtx = fz_rotate( 270 ); 368 | break; 369 | } 370 | 371 | mMtx = fz_scale( rwZoom, rhZoom ); 372 | 373 | rBox = fz_bound_page( mCtx, mPage ); 374 | iBox = fz_round_rect( fz_transform_rect( rBox, mMtx ) ); 375 | rBox = fz_rect_from_irect( iBox ); 376 | 377 | /** Necessary: otherwise only a part of the page is rendered */ 378 | iBox.x1 *= rwZoom; 379 | iBox.y1 *= rhZoom; 380 | 381 | fz_try( mCtx ) { 382 | image = fz_new_pixmap_with_bbox( mCtx, colorspace, iBox, 0, 1 ); 383 | fz_clear_pixmap_with_value( mCtx, image, 0xff ); 384 | fz_device *dev = fz_new_draw_device_with_bbox( mCtx, mMtx, image, &iBox ); 385 | 386 | fz_run_page( mCtx, mPage, dev, mMtx, NULL ); 387 | } 388 | 389 | fz_catch( mCtx ) { 390 | 391 | fprintf( stderr, "Cannot render page: %s\n", fz_caught_message( mCtx ) ) ; 392 | fz_drop_page( mCtx, mPage ); 393 | fz_drop_colorspace( mCtx, colorspace ); 394 | return QImage(); 395 | } 396 | 397 | QImage img = QImage( image->samples, ( iBox.x1 - iBox.x0 ), ( iBox.y1 - iBox.y0 ), QImage::Format_ARGB32 ); 398 | 399 | return img; 400 | }; 401 | 402 | QString MuPage::pageText() const { 403 | 404 | QString ret; 405 | fz_stext_page *spg = NULL; 406 | fz_buffer *buff = NULL; 407 | fz_output *output = NULL; 408 | 409 | fz_try( mCtx ) { 410 | 411 | /** fz_stext_page */ 412 | spg = fz_new_stext_page_from_page( mCtx, mPage, 0 ); 413 | 414 | /** Buffer 1MiB = 1 * 1024 * 1024 */ 415 | buff = fz_new_buffer( mCtx, 1024 * 1024 ); 416 | 417 | /** Create fz_output */ 418 | output = fz_new_output_with_buffer( mCtx, buff ); 419 | 420 | /** Print it to text buffer */ 421 | fz_print_stext_page_as_text( mCtx, output, spg ); 422 | 423 | ret = QString::fromUtf8( fz_string_from_buffer( mCtx, buff ) ); 424 | } 425 | 426 | fz_always( mCtx ) { 427 | 428 | fz_drop_buffer( mCtx, buff ); 429 | fz_drop_output( mCtx, output ); 430 | fz_drop_stext_page( mCtx, spg ); 431 | } 432 | 433 | fz_catch( mCtx ) { 434 | 435 | fprintf( stderr, "Unable to extract text from page: %s\n", fz_caught_message( mCtx ) ); 436 | } 437 | 438 | return ret; 439 | }; 440 | 441 | QString MuPage::text( QRectF rect ) const { 442 | 443 | QString ret; 444 | fz_stext_page *textPage; 445 | fz_point a, b; 446 | char *str; 447 | 448 | a.x = rect.left(); 449 | a.y = rect.top(); 450 | b.x = rect.right(); 451 | b.y = rect.bottom(); 452 | 453 | fz_try( mCtx ) { 454 | /** Structured text page */ 455 | textPage = fz_new_stext_page_from_page( mCtx, mPage, 0 ); 456 | 457 | /** Copy the text from selection */ 458 | str = fz_copy_selection( mCtx, textPage, a, b, 0); 459 | } 460 | 461 | fz_always( mCtx ) { 462 | ret = QString::fromUtf8( str ); 463 | free( str ); 464 | fz_drop_stext_page( mCtx, textPage ); 465 | } 466 | 467 | fz_catch( mCtx ) { 468 | 469 | fprintf( stderr, "Unable to extract text from page: %s\n", fz_caught_message( mCtx ) ); 470 | } 471 | 472 | return ret; 473 | }; 474 | 475 | QList MuPage::search( QString query, PdfWidget::RenderOptions opts ) const { 476 | 477 | QList ret; 478 | fz_stext_page *spg = NULL; 479 | fz_quad quads[ 1024 ] = { 0 }; 480 | int count = 0; 481 | 482 | int fz_search_stext_page(fz_context *ctx, fz_stext_page *text, const char *needle, fz_quad *quads, int max_quads); 483 | 484 | fz_try( mCtx ) { 485 | 486 | /** fz_stext_page */ 487 | spg = fz_new_stext_page_from_page( mCtx, mPage, 0 ); 488 | 489 | /** Search the text in this page */ 490 | count = fz_search_stext_page( mCtx, spg, query.toUtf8().data(), quads, 1024 ); 491 | } 492 | 493 | fz_always( mCtx ) { 494 | 495 | fz_drop_stext_page( mCtx, spg ); 496 | } 497 | 498 | fz_catch( mCtx ) { 499 | 500 | fprintf( stderr, "Unable to search text in page: %s\n", fz_caught_message( mCtx ) ); 501 | } 502 | 503 | return ret; 504 | }; 505 | --------------------------------------------------------------------------------