├── 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 |
--------------------------------------------------------------------------------