Compare commits

...

195 Commits

Author SHA1 Message Date
Jakub Melka c9b262fc36 Update of readme - flatpak/appimage 2024-04-01 10:50:11 +02:00
Jakub Melka 29f59be3b6 Correct type 2024-04-01 10:38:54 +02:00
Jakub Melka 793cf59c72 Contributor license agreement - change of name to correct 2024-04-01 10:37:02 +02:00
Jakub Melka 1e52c0c063 Issue #173: errors loading file Echoplex.pdf 2024-03-21 15:29:29 +01:00
Jakub Melka 8b832ccab9 Issue #172: access keys are missing from most menu items/action text strings 2024-03-21 13:16:52 +01:00
Jakub Melka bf4b0552dc Merge remote-tracking branch 'remotes/origin/braches/issue159' 2024-03-19 20:01:36 +01:00
Jakub Melka b4e742f564 Issue #159: Linux fix 2024-03-18 20:14:03 +01:00
Jakub Melka 35242f845e Issue #159: Fix 2024-03-18 07:46:33 +01:00
Jakub Melka ccd69e1ac4 Issue #159: Compilation fix 2024-03-17 14:36:24 +01:00
Jakub Melka c11708d367 Issue #159: Adjust desktop files 2024-03-17 14:00:16 +01:00
Jakub Melka f2ea50ae6e Issue #159: Launchpad application 2024-03-17 13:29:24 +01:00
Jakub Melka a72f2f7bac Issue #159: Linux compilation fix 2024-03-16 18:04:11 +01:00
Jakub Melka 032e564fd8 Issue #159: Compilation fix 2024-03-16 17:40:27 +01:00
Jakub Melka 28807b4f12 Issue #159: Renaming applications 2024-03-16 17:02:44 +01:00
Jakub Melka a70f45c8a9 Issue #168: When opening a PDF file or merging some PDF files, stamp will disappear. 2024-02-29 19:40:43 +01:00
Jakub Melka 344c341f65 Issue #163: Unable to render probably valid PDF 2024-02-27 19:58:33 +01:00
Jakub Melka d6f334c242 Issue #164: Taskbar icon not shown in linux mint. 2024-02-27 19:37:41 +01:00
Jakub Melka bdf7a957d5 Update of README (Year) 2024-02-25 16:22:07 +01:00
Jakub Melka 5f0ae6ae5f Update of RELEASES.txt 2024-02-25 16:10:12 +01:00
Jakub Melka 6c5b8b08a5 Merge remote-tracking branch 'remotes/origin/branches/issue123' 2024-02-25 16:08:24 +01:00
Jakub Melka 1c3eca3971 Issue #123: Added version of Blend2D 2024-02-25 15:47:39 +01:00
Jakub Melka 03cbde9690 Issue #123: Final bugfixing 2024-02-25 15:19:35 +01:00
Jakub Melka 89cfd1dd1f Issue #123: Compilation fix 2024-02-24 19:15:57 +01:00
Jakub Melka e8d72878a5 Issue #123: Update workflow 2024-02-24 18:00:03 +01:00
Jakub Melka 2e38e41ce9 Issue #123: Clipping lines 2024-02-24 17:56:22 +01:00
Jakub Melka 6a477bdf04 Issue #123: Drawing clipped texts 2024-02-22 20:25:52 +01:00
Jakub Melka 54d093ab8c Issue #123: Clipping images 2024-02-22 19:43:43 +01:00
Jakub Melka 5eb5069173 Issue #123: Oprava klipování 2024-02-18 19:36:35 +01:00
Jakub Melka 7ad04b55ee Issue #123: Clipping 2024-02-17 17:48:50 +01:00
Jakub Melka f80b7b059e Issue #123: Drawing texts, finishing painter 2024-02-11 13:58:07 +01:00
Jakub Melka d1d0fe30d6 Issue #123: DPI scaling 2024-02-10 18:42:58 +01:00
Jakub Melka f3e1a94e1c Issue #123: Blend2D painting implementation 2024-02-10 18:04:58 +01:00
Jakub Melka d314683d38 Issue #123: Alternative software rendering backend 2024-02-04 18:05:38 +01:00
Jakub Melka 87cedf01dc Issue #161: Can it be possible to trust a certificate like in acrobat? 2024-02-03 19:25:43 +01:00
Jakub Melka 1bf7b724a1 Issue #157: debian .deb release 2024-02-03 11:59:23 +01:00
Jakub Melka 8406fd0c47 Merge remote-tracking branch 'remotes/origin/branches/linuxinstall' 2024-01-21 15:39:13 +01:00
Jakub Melka 0629a719bd Linux install: Bugfixing 2024-01-21 15:25:49 +01:00
Jakub Melka e45924a4cc Linux install: Desktop icon fix 2024-01-21 14:53:08 +01:00
Jakub Melka fc60e94156 Linux install: Bugfixing 2024-01-21 14:35:26 +01:00
Jakub Melka 0f8e2b7012 Linux install: Bugfix 2024-01-21 14:21:09 +01:00
Jakub Melka afeaf88151 Linux build: AppImage 2024-01-21 14:08:14 +01:00
Jakub Melka c0eaeddcd9 Linux install: Bugfixing 2024-01-21 13:44:44 +01:00
Jakub Melka 2019816995 Linux install: Bugfixing 2024-01-21 13:33:08 +01:00
Jakub Melka 2aea7ed606 Linux install: Bugfixing 2024-01-21 13:12:07 +01:00
Jakub Melka cb98f3bcb2 Linux install: Bugfixing 2024-01-21 12:57:30 +01:00
Jakub Melka 64fae4feba Linux install: Space fix 2024-01-21 12:39:01 +01:00
Jakub Melka 56095ab350 Linux install: Bugfixing 2024-01-21 12:37:31 +01:00
Jakub Melka 41b89c2988 Linux Install: Bugfixing 2024-01-21 12:34:57 +01:00
Jakub Melka a6d201e3a5 Reapply "Linux installation: Deploy Qt"
This reverts commit 04c7855d7e.
2024-01-21 12:26:44 +01:00
Jakub Melka 04c7855d7e Revert "Linux installation: Deploy Qt"
This reverts commit 86a32de1d1.
2024-01-21 12:24:09 +01:00
Jakub Melka 86a32de1d1 Linux installation: Deploy Qt 2024-01-21 12:10:23 +01:00
Jakub Melka b8ff31c5e5 Linux install: GCC 11 2024-01-21 11:50:52 +01:00
Jakub Melka a27d8be0e0 Linux install: Setup GCC 2024-01-21 11:43:41 +01:00
Jakub Melka 1bf4e90b8c Workflow: Linux install initial commit 2024-01-21 11:20:31 +01:00
Nyall Dawson 4f1fca4b70 Remove unused member 2024-01-14 13:54:48 +01:00
Nyall Dawson 52ce99d466 Fix unused lambda capture warning 2024-01-14 13:54:48 +01:00
Nyall Dawson eefde4edee Fix comparison of different signedness warning 2024-01-14 13:54:48 +01:00
Nyall Dawson 61f489dd70 Fix "type qualifiers ignored on cast result type" warning 2024-01-13 17:53:20 +01:00
Nyall Dawson 7ab77c582b Fix false positive uninintialized member warning 2024-01-13 17:53:20 +01:00
Nyall Dawson 577866aa2f Fix comparison of integer expressions of different signedness warnings 2024-01-13 17:53:20 +01:00
Nyall Dawson bbecbf6311 Remove impossible < 0 checks for size_t 2024-01-13 17:53:20 +01:00
Nyall Dawson 6354e4cad1 Fix build failure using clang compiler 2024-01-13 17:50:41 +01:00
Nyall Dawson 3846c5187e Add extra includes to get build running for core lib only 2024-01-13 15:44:36 +01:00
Nyall Dawson 8c40e49801 Add missing break 2024-01-13 15:43:39 +01:00
Nyall Dawson 2ed31dcd2c Use QString reference instead of copy in loop 2024-01-13 15:42:42 +01:00
Jakub Melka 221587c751 Update of io.github.JakubMelka.Pdf4qt.appdata.xml 2024-01-11 20:08:04 +01:00
Jakub Melka 3cabc6b792 Update of required Qt version 2024-01-11 20:04:12 +01:00
Jakub Melka b2b033b5d3 Release of version 1.3.7 2024-01-10 19:06:53 +01:00
Jakub Melka 9bbf4539d1 Issue #96: PDF4QT crashes when I open PDF 2024-01-07 11:41:45 +01:00
Jakub Melka 843c025010 Issue #142: Cannot reach the top 2024-01-05 19:57:45 +01:00
Jakub Melka ca698156cd Compilation fix 2024-01-05 19:28:31 +01:00
Jakub Melka 298060a61f Issue #141: Save button in toolbar 2023-12-30 19:13:17 +01:00
Jakub Melka b62e96e2d0 Fix of RELEASES.txt 2023-12-30 18:33:16 +01:00
Jakub Melka 62abee0e97 Issue #140: New bookmarks created empty? 2023-12-30 17:42:38 +01:00
Jakub Melka 1a66b804a2 Issue #139: Changing page layout reset the current page 2023-12-30 16:45:27 +01:00
Jakub Melka 8338d7d85d Issue #102: Thumbnails page size fix 2023-12-29 20:03:38 +01:00
Jakub Melka acafeb0144 Oprava kompilace 2023-12-29 19:13:06 +01:00
Jakub Melka 0ddeda8036 Issue #133: Rectangle selector when choosing the page of the PDF 2023-12-29 18:40:32 +01:00
Jakub Melka 1fded3d6b7 Issue #133: Rectangle selector when choosing the page of the PDF 2023-12-28 19:37:38 +01:00
Jakub Melka 333ccb1bfb Badge for build process 2023-12-28 18:42:10 +01:00
Jakub Melka e4875c4050 Issue #137: Redaction - Cannot convert '#000000' to color value 2023-12-28 18:33:06 +01:00
Jakub Melka 905a9e4a8b Build fix 2023-12-28 18:00:45 +01:00
Jakub Melka d6e5dd2b15 Update of RELEASES.txt 2023-12-26 19:49:11 +01:00
Jakub Melka 3ccbef6dc8 Issue #104: Try to fix license 2023-12-26 19:46:56 +01:00
Jakub Melka 37654945d2 Try to fix license 2023-12-26 19:43:39 +01:00
Jakub Melka d5e390e75c Merge remote-tracking branch 'remotes/origin/branches/issue134' 2023-12-26 18:45:14 +01:00
Jakub Melka 7cb6b5bb3a Issue #134: Bugfixing 2023-12-26 18:44:28 +01:00
Jakub Melka a085a54b00 Issue #134: Add search bar for actions 2023-12-25 14:39:47 +01:00
Jakub Melka c6d8b8b783 Merge remote-tracking branch 'remotes/origin/branches/issue128' 2023-12-25 11:58:01 +01:00
Jakub Melka 0f47f1a6d0 Issue #128: Update of RELEASES.txt 2023-12-25 11:40:55 +01:00
Jakub Melka 5ba4cef2f7 Issue #128: Create list of markup annotations 2023-12-25 11:39:20 +01:00
Jakub Melka 89ea815696 Issue #128: Create list of markup annotations 2023-12-24 19:03:28 +01:00
Jakub Melka 53849f51e1 Issue #129: Cannot compile with lcms 2.16 2023-12-24 12:01:15 +01:00
Jakub Melka 9de8dbfad2 Update of RELEASES.txt 2023-12-24 11:02:22 +01:00
Jakub Melka 94b392c108 Merge remote-tracking branch 'remotes/origin/branches/issue55' 2023-12-24 11:01:12 +01:00
Jakub Melka e082f072f7 Issue #55: Oprava kompilace pro Windows 2023-12-23 17:32:12 +01:00
Jakub Melka d974912b05 Issue #55: Fix signing documents using Windows Certificate Store 2023-12-23 17:13:24 +01:00
Jakub Melka 56f5c4abcf Issue #55: Windows implementation 2023-12-23 15:30:17 +01:00
Jakub Melka 17f94a102c Issue #55: Refactoring of certificates 2023-12-22 19:12:35 +01:00
Jakub Melka b3580560a4 Update of RELEASES.txt 2023-12-21 15:06:31 +01:00
Jakub Melka 9f624e5569 Issue #126: Remove <QtCore> include from main headers 2023-12-21 14:25:41 +01:00
Jakub Melka e5e25a71a3 Remove <QtCore> include 2023-12-21 12:48:31 +01:00
Jakub Melka c79a029c2f Revert "Avoid QtCore import, which results in ALL Qt core headers being imported"
This reverts commit c17165b088.
2023-12-20 21:18:47 +01:00
Nyall Dawson c17165b088 Avoid QtCore import, which results in ALL Qt core headers being imported 2023-12-20 20:48:54 +01:00
Jakub Melka 4a679efe25 Add option to build only core library 2023-12-18 20:11:06 +01:00
Jakub Melka d07263c3f1 Update of RELEASES.txt 2023-12-17 19:13:05 +01:00
Jakub Melka 5d001ede45 Merge remote-tracking branch 'remotes/origin/branches/issue54' 2023-12-17 19:11:46 +01:00
Jakub Melka 1ed7a12357 Issue #54: Linux compilation 2023-12-17 18:38:45 +01:00
Jakub Melka e87b14dc3a Issue #54: Final bugfix 2023-12-17 18:14:25 +01:00
Jakub Melka e9ca3a4a82 Issue #54: Finishing of bookmarking 2023-12-17 18:11:49 +01:00
Jakub Melka 7a5f37e38f Issue #54: Bookmarks page - model, bookmarks manager 2023-12-16 20:23:53 +01:00
Jakub Melka c1c59139b5 Issue #54: Rename bookmarks 2023-12-13 20:14:33 +01:00
Jakub Melka 27cccbedcb Adjust build system for Freetype and LCMS (recommended settings) 2023-12-13 11:05:29 +01:00
Jakub Melka 15e7b93393 CI: Finish work 2023-12-11 20:03:08 +01:00
Jakub Melka 3645bfe07b CI: Bugfixing 2023-12-11 19:24:30 +01:00
Jakub Melka 2ad471ee9a CI: Bugfixing 2023-12-11 19:21:53 +01:00
Jakub Melka 657afadd46 CI: Update archive 2023-12-10 19:27:04 +01:00
Jakub Melka 8759578142 CI: Specify parameter to MSBUILD 2023-12-10 18:32:25 +01:00
Jakub Melka 6721490ee6 CI: Install ninja 2023-12-10 18:12:39 +01:00
Jakub Melka e6d95d3936 CI: Use Ninja Build 2023-12-10 17:56:33 +01:00
Jakub Melka d80351b2a6 CI: Bugfixing 2023-12-10 17:26:24 +01:00
Jakub Melka 38988babc5 CI: Echo CMAKE COMMAND 2023-12-10 16:24:58 +01:00
Jakub Melka 14ae5e9a85 CI: Update build command 2023-12-10 15:23:06 +01:00
Jakub Melka 038101d765 CI: Windows - fix paths, upload zip 2023-12-10 15:01:40 +01:00
Jakub Melka 8e6e83cc66 CI: Windows build script 2023-12-10 14:21:13 +01:00
Jakub Melka feade42fe8 Update of RELEASES.txt 2023-12-10 13:58:40 +01:00
Jakub Melka 277b40acc9 Merge remote-tracking branch 'remotes/origin/branches/issue112' 2023-12-10 13:56:01 +01:00
Jakub Melka 2c0b462075 Issue #112: Interval fix 2023-12-10 13:55:35 +01:00
Jakub Melka 4340b3dbaa Issue #112: smooth scrolling 2023-12-10 13:07:06 +01:00
Jakub Melka 0b579c828f CI: Cache build trees, update some action versions 2023-12-09 19:43:01 +01:00
Jakub Melka ee42c63f80 CI: Add dependency multimedia 2023-12-09 19:11:10 +01:00
Jakub Melka 4b76eb989d CI: Include Qt Speech module 2023-12-09 19:03:00 +01:00
Jakub Melka 3e9d7a39ff CI: Qt skip modules 2023-12-09 18:42:56 +01:00
Jakub Melka 5f7b54dff5 CI: Qt module dependencies 2023-12-09 18:20:08 +01:00
Jakub Melka 1dcb42ebef CI: Upload artifact fix 2023-12-09 17:43:16 +01:00
Jakub Melka 19a26c2a74 CI: Bugfixing 2023-12-09 17:34:48 +01:00
Jakub Melka 176369e8dd CI: Another fix 2023-12-09 17:24:16 +01:00
Jakub Melka 1aa3ffe695 CI: Fix yaml syntax 2023-12-09 17:23:19 +01:00
Jakub Melka 31e34d8e32 CI: Linuxu ubuntu 2023-12-09 17:22:21 +01:00
Jakub Melka d50ecdbb28 Issue #119: Improve search bar 2 (the revenge) 2023-12-09 15:41:08 +01:00
Jakub Melka 5a6f448467 Remove not needed dependencies 2023-12-09 13:55:48 +01:00
Jakub Melka 147a1ea586 Issue #113: Color | Custom (green/black) partially works in scanned PDF (1.3.6) 2023-12-08 14:44:51 +01:00
Jakub Melka 8db0ae80c3 Merge remote-tracking branch 'remotes/origin/branches/splitlibraries' 2023-12-08 11:55:18 +01:00
Jakub Melka 3004618992 Issue #118: Header files and installer fixes 2023-12-08 11:54:12 +01:00
Jakub Melka 642e6a9bb7 Issue #118: Fixing compilation errors 2023-12-08 10:54:29 +01:00
Jakub Melka cdbbe5e121 Issue #118: Move compiler and draw space controller 2023-12-07 20:18:28 +01:00
Jakub Melka 0e1959b3aa Issue #118: Refactoring of forms finished 2023-12-07 17:53:50 +01:00
Jakub Melka b4d123baac Issue #118: Refactoring of forms 2023-12-06 20:58:35 +01:00
Jakub Melka edd100d3b8 Issue #118: Continuation 2023-12-04 20:04:40 +01:00
Jakub Melka bc8be2198b Issue #118: First part of splitting 2023-12-03 19:11:17 +01:00
Jakub Melka c01a1da4ec Issue #115: Redesign of sidebar widget, new icons 2023-12-03 15:25:06 +01:00
Jakub Melka 6221c533a2 Update of readme 2023-12-02 18:41:30 +01:00
Jakub Melka 1a10401b91 Issue #118: Adding CMAKE options for minimal builds 2023-12-02 18:35:11 +01:00
Jakub Melka 2d1e1dc479 Issue #116: Draw dialog title bar 2023-12-02 16:03:27 +01:00
Jakub Melka 288eead65e Issue #116: Navigate to text 2023-12-02 15:40:11 +01:00
Jakub Melka a892c192fc Issue #116: Improve search bar (rembember searched text, allow scroll and zoom) 2023-12-02 12:10:50 +01:00
Jakub Melka 1c5c7da5ba Issue #99: Icons for dark mode 2023-11-26 19:15:20 +01:00
Jakub Melka f5cb2a17af Release of version 1.3.4 2023-11-24 18:15:31 +01:00
Jakub Melka 5f678bc308 Update of RELEASES.txt 2023-11-24 18:00:22 +01:00
Jakub Melka ff6dd4b249 Issue #110: PDF4QT Viewer Lite : Arbitrary Code can execute when using Send by Email 2023-11-21 19:43:04 +01:00
Jakub Melka 851374dc73 Linux Compilation Fix III 2023-11-19 18:06:13 +01:00
Jakub Melka 5746412e31 Linux compilation fix II 2023-11-19 18:02:32 +01:00
Jakub Melka e476c4ea11 Linux compilation fix 2023-11-19 17:57:12 +01:00
Jakub Melka ed79aa0334 Update: Compilation fix for Qt 6.6, update of RELEASES.txt 2023-11-19 15:41:42 +01:00
Jakub Melka 65fd88aa71 Issue #108: Add accessibility options in pdf reader [enhancement] - settings in ui, finish work 2023-11-19 14:28:23 +01:00
Jakub Melka 6f6ddaab04 Issue #108: Add accessibility options in pdf reader 2023-11-18 18:52:18 +01:00
Jakub Melka 2408c61b5f Bitonic -> Bitonal 2023-11-17 19:40:05 +01:00
Jakub Melka 4ffd4a0639 Issue #109: No text, font. Parts missing 2023-11-17 18:49:00 +01:00
Jakub Melka e9a87553af Merge remote-tracking branch 'remotes/origin/branches/issue107' 2023-11-17 16:20:05 +01:00
Jakub Melka 47f0bffeca Issue #107: Bugfixing 2023-11-17 16:07:50 +01:00
Jakub Melka 805c967b70 Issue #107: Create document with converted bitonic images 2023-11-17 15:25:25 +01:00
Jakub Melka c5ddb521ed Issue #107: Conversion algorithm 2023-11-17 13:45:49 +01:00
Jakub Melka cf7d65dc82 Issue #107: Enable/Disable image conversion GUI 2023-11-17 11:00:46 +01:00
Jakub Melka fc44dfa4bc Issue #107: Loading images 2023-11-16 19:40:00 +01:00
Jakub Melka 908fb47af1 Issue #107: Add scanned pdf conversion to bitonal [enhancement] 2023-11-11 17:33:32 +01:00
Jakub Melka 881364f0a0 Issue #106: Warning - Hardware acceleration is not supported on this device 2023-11-08 19:32:50 +01:00
Jakub Melka 6fe978f031 Issue #103: Bookmark sidebar greyed out if a bookmark is not already present 2023-11-08 19:24:04 +01:00
Jakub Melka 2584227373 Issue #104: Try to solve license problem 2023-11-05 14:15:16 +01:00
Jakub Melka 1631268d08 Sponsor button 2023-10-22 16:07:55 +02:00
Jakub Melka 9a951431c4 Sponsor v readme 2023-10-21 16:50:28 +02:00
Jakub Melka 3a50c16c07 Update of RELEASES.txt 2023-10-18 20:13:55 +02:00
Jakub Melka 3d32db2046 Issue #100: Annotation rectangle 2023-10-18 20:11:43 +02:00
Jakub Melka edc86a84fa Funding 2023-10-15 16:19:24 +02:00
Jakub Melka 10f24c2dff Issue #97: Context menu + layout items on window size changed 2023-10-07 18:24:04 +02:00
Jakub Melka c57f28a3b5 Issue #97: Add drag and drop capability to DocPage Organizer 2023-10-07 17:57:43 +02:00
Jakub Melka 52f6a3ce8a Merge remote-tracking branch 'remotes/origin/branches/issue76' 2023-10-07 16:47:09 +02:00
Jakub Melka 93496339d4 Issue #76: Finished 2023-10-07 16:43:12 +02:00
Jakub Melka 73024fbe99 Issue #76: Modify document, when bookmarks are changed 2023-10-07 16:21:26 +02:00
Jakub Melka bf53e7419b Issue #76: Drag and drop 2023-10-07 15:40:45 +02:00
Jakub Melka be0d02bb5c Issue #76: Basic functionality of outline editing 2023-10-01 17:35:42 +02:00
Jakub Melka bf4ed862e5 Linux compilation fix 2023-09-30 14:16:49 +02:00
Jakub Melka a29a35e029 Issue #83: Is it possible to specify a default font for a pdf when the font is not load or recognize? 2023-09-29 18:09:07 +02:00
Jakub Melka c2c03a358f Issue #94: Update of deb package file 2023-09-23 19:32:11 +02:00
Jakub Melka 9b33b3a4a5 Issue #94: New directory structure 2023-09-23 18:07:38 +02:00
Jakub Melka 07c2a476a0 Revert "Flatpak test"
This reverts commit 0aec1a7358.
2023-09-22 19:45:38 +02:00
1114 changed files with 147908 additions and 137468 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
github: JakubMelka

105
.github/workflows/LinuxInstall.yml vendored Normal file
View File

@ -0,0 +1,105 @@
name: LinuxInstall
on:
create:
tags:
- 'v*'
workflow_dispatch:
jobs:
build_ubuntu:
runs-on: ubuntu-20.04
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libxcb-cursor0
sudo apt-get install -y libspeechd2
- name: Checkout repository
uses: actions/checkout@v4
with:
path: pdf4qt
- name: Set up GCC
uses: egor-tensin/setup-gcc@v1
with:
version: 11
platform: x64
- name: 'VCPKG: Set up VCPKG'
run: |
git clone --depth=1 https://github.com/microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
- name: 'VCPKG: Cache vcpkg dependencies'
uses: actions/cache@v3
with:
path: |
./vcpkg/downloads
./vcpkg/packages
key: ${{ runner.os }}-vcpkg-v2-${{ hashFiles('**/vcpkg.json') }}
restore-keys: |
${{ runner.os }}-vcpkg-v2-
- name: 'VCPKG: Install project dependencies'
run: |
./vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng blend2d
working-directory: vcpkg
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: '6.6.0'
host: 'linux'
target: 'desktop'
dir: '${{ github.workspace }}/qt/'
install-deps: 'true'
modules: 'qtspeech qtmultimedia'
cache: 'true'
cache-key-prefix: ${{ runner.os }}-qt-660
- name: Build project
working-directory: pdf4qt
run: |
cmake -B build -S . -DPDF4QT_INSTALL_QT_DEPENDENCIES=0 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -DVCPKG_OVERLAY_PORTS=vcpkg/overlays -DPDF4QT_INSTALL_TO_USR=ON
cmake --build build -j6
cmake --install build
cp -rp build/install build/install_appimage
- name: 'Linux Deploy Qt'
working-directory: pdf4qt/build
run: |
wget -O deploy.AppImage https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
chmod +x deploy.AppImage
./deploy.AppImage install/usr/share/applications/io.github.JakubMelka.Pdf4qt.desktop -executable-dir=install/usr/bin -extra-plugins=iconengines,imageformats,texttospeech
- name: Make DEB package
working-directory: pdf4qt/build
run: |
sh make-package.sh
- name: Upload DEB package
uses: actions/upload-artifact@v3
with:
name: ubuntu-deb-package
path: ./pdf4qt/build/*.deb
retention-days: 30
- name: 'Make AppImage'
working-directory: pdf4qt/build
run: |
cp install_appimage/usr/share/icons/hicolor/scalable/apps/io.github.JakubMelka.Pdf4qt.svg install_appimage/io.github.JakubMelka.Pdf4qt.svg
./deploy.AppImage install_appimage/usr/share/applications/io.github.JakubMelka.Pdf4qt.desktop -appimage -executable-dir=install_appimage/usr/bin -always-overwrite -extra-plugins=iconengines,imageformats,texttospeech
- name: Upload AppImage package
uses: actions/upload-artifact@v3
with:
name: ubuntu-appimage
path: ./pdf4qt/build/*.AppImage
retention-days: 30

132
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,132 @@
name: CI
on:
push:
branches:
- master
workflow_dispatch:
jobs:
build_ubuntu:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
path: pdf4qt
- name: 'VCPKG: Set up VCPKG'
run: |
git clone --depth=1 https://github.com/microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
- name: 'VCPKG: Cache vcpkg dependencies'
uses: actions/cache@v3
with:
path: |
./vcpkg/downloads
./vcpkg/packages
key: ${{ runner.os }}-vcpkg-v2-${{ hashFiles('**/vcpkg.json') }}
restore-keys: |
${{ runner.os }}-vcpkg-v2-
- name: 'VCPKG: Install project dependencies'
run: |
./vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng blend2d
working-directory: vcpkg
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: '6.6.0'
host: 'linux'
target: 'desktop'
dir: '${{ github.workspace }}/qt/'
install-deps: 'true'
modules: 'qtspeech qtmultimedia'
cache: 'true'
cache-key-prefix: ${{ runner.os }}-qt-660
- name: Build project
working-directory: pdf4qt
run: |
cmake -B build -S . -DPDF4QT_INSTALL_QT_DEPENDENCIES=0 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release
cmake --build build -j6
cmake --install build
- name: Make DEB package
working-directory: pdf4qt/build
run: |
sh make-package.sh
- name: Upload DEB package
uses: actions/upload-artifact@v3
with:
name: ubuntu-deb-package
path: ./pdf4qt/build/*.deb
retention-days: 30
build_windows:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
path: pdf4qt
- name: 'VCPKG: Set up VCPKG'
run: |
git clone --depth=1 https://github.com/microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat -disableMetrics
.\vcpkg integrate install
set VCPKG_ROOT=${env:GITHUB_WORKSPACE}\vcpkg\
set "VCPKG_BINARY_SOURCES=clear;files,${env:GITHUB_WORKSPACE}\vcpkg\archives,readwrite"
- name: 'VCPKG: Cache vcpkg dependencies'
uses: actions/cache@v3
with:
path: |
./vcpkg/downloads
./vcpkg/packages
./vcpkg/installed
./vcpkg/archives
key: ${{ runner.os }}-vcpkg-${{ hashFiles('**/vcpkg.json') }}
- name: 'VCPKG: Install project dependencies'
run: |
.\vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng blend2d --triplet x64-windows
working-directory: vcpkg
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: '6.6.0'
host: 'windows'
target: 'desktop'
dir: '${{ github.workspace }}/qt/'
install-deps: 'true'
modules: 'qtspeech qtmultimedia'
cache: 'true'
cache-key-prefix: ${{ runner.os }}-qt-660
- name: Build project
working-directory: pdf4qt
shell: pwsh
run: |
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release -DPDF4QT_INSTALL_QT_DEPENDENCIES=ON -DPDF4QT_INSTALL_DEPENDENCIES=ON -DCMAKE_TOOLCHAIN_FILE="${env:GITHUB_WORKSPACE}\vcpkg\scripts\buildsystems\vcpkg.cmake" -DPDF4QT_QT_ROOT="${env:Qt6_DIR}" -DPDF4QT_INSTALL_MSVC_REDISTRIBUTABLE=ON -DPDF4QT_INSTALL_PREPARE_WIX_INSTALLER=ON -DPDF4QT_INSTALL_TO_USR=ON
cmake --build build --config Release -j6
cmake --install build
- name: Upload Windows package
uses: actions/upload-artifact@v3
with:
name: 'pdf4qt-${{ runner.os }}.zip'
path: .\pdf4qt\build\install\usr\bin
retention-days: 30

2
.licensee.yml Normal file
View File

@ -0,0 +1,2 @@
ignore:
- "LICENSE.rtf"

View File

@ -1,4 +1,4 @@
# Copyright (C) 2022 Jakub Melka
# Copyright (C) 2023 Jakub Melka
#
# This file is part of PDF4QT.
#
@ -17,7 +17,8 @@
cmake_minimum_required(VERSION 3.16)
set(PDF4QT_VERSION 1.3.5)
set(PDF4QT_VERSION 1.3.7)
message(STATUS "Build type - CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
project(PDF4QT VERSION ${PDF4QT_VERSION} LANGUAGES CXX)
@ -32,6 +33,8 @@ if(WIN32 AND MSVC)
option(PDF4QT_INSTALL_PREPARE_WIX_INSTALLER "Prepare Wix installer for Windows" ON)
endif()
option(PDF4QT_BUILD_ONLY_CORE_LIBRARY "Build only core library" OFF)
set(PDF4QT_QT_ROOT "" CACHE PATH "Qt root directory")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
@ -43,16 +46,22 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Svg Xml PrintSupport TextToSpeech OpenGL OpenGLWidgets Multimedia Network Test)
if(PDF4QT_BUILD_ONLY_CORE_LIBRARY)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Svg Xml)
else()
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Svg Xml PrintSupport TextToSpeech Test)
endif()
qt_standard_project_setup()
find_package(OpenSSL REQUIRED)
find_package(lcms REQUIRED)
find_package(ZLIB REQUIRED)
find_package(freetype CONFIG REQUIRED)
find_package(Freetype REQUIRED)
find_package(OpenJPEG CONFIG REQUIRED)
find_package(JPEG REQUIRED)
find_package(PNG REQUIRED)
find_package(blend2d CONFIG REQUIRED)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
@ -80,33 +89,87 @@ if (LINUX_GCC)
find_package(TBB REQUIRED)
endif()
add_subdirectory(Pdf4QtLib)
add_subdirectory(CodeGenerator)
add_subdirectory(JBIG2_Viewer)
add_subdirectory(PdfExampleGenerator)
add_subdirectory(PdfTool)
add_subdirectory(UnitTests)
add_subdirectory(Pdf4QtViewer)
add_subdirectory(Pdf4QtViewerPlugins)
add_subdirectory(Pdf4QtViewerProfi)
add_subdirectory(Pdf4QtViewerLite)
add_subdirectory(Pdf4QtDocPageOrganizer)
add_subdirectory(Pdf4QtDocDiff)
add_subdirectory(WixInstaller)
option(PDF4QT_INSTALL_TO_USR "Install to usr directory" ON)
if(PDF4QT_LINUX)
set(PDF4QT_INSTALL_LIB_DIR_IMPL lib)
set(PDF4QT_INSTALL_BIN_DIR_IMPL bin)
# Check if VCPKG_OVERLAY_PORTS is set as an environment variable or a CMake argument
if(NOT DEFINED ENV{VCPKG_OVERLAY_PORTS} AND NOT DEFINED VCPKG_OVERLAY_PORTS)
message(WARNING "The VCPKG_OVERLAY_PORTS variable is not set! Application can crash in Open/Save dialog due to incompatible LIBPNG.")
else()
set(VCPKG_OVERLAY_PORTS_VALUE "$ENV{VCPKG_OVERLAY_PORTS}")
if(DEFINED VCPKG_OVERLAY_PORTS)
set(VCPKG_OVERLAY_PORTS_VALUE "${VCPKG_OVERLAY_PORTS}")
endif()
message(STATUS "The VCPKG_OVERLAY_PORTS variable is set to: ${VCPKG_OVERLAY_PORTS_VALUE}")
endif()
else()
set(PDF4QT_INSTALL_LIB_DIR_IMPL bin)
set(PDF4QT_INSTALL_BIN_DIR_IMPL bin)
endif()
if(PDF4QT_INSTALL_TO_USR)
set(PDF4QT_INSTALL_LIB_DIR usr/${PDF4QT_INSTALL_LIB_DIR_IMPL})
set(PDF4QT_INSTALL_BIN_DIR usr/${PDF4QT_INSTALL_BIN_DIR_IMPL})
set(PDF4QT_INSTALL_SHARE_DIR usr/share)
else()
set(PDF4QT_INSTALL_LIB_DIR ${PDF4QT_INSTALL_LIB_DIR_IMPL})
set(PDF4QT_INSTALL_BIN_DIR ${PDF4QT_INSTALL_BIN_DIR_IMPL})
set(PDF4QT_INSTALL_SHARE_DIR share)
endif()
add_subdirectory(Pdf4QtLibCore)
if(NOT PDF4QT_BUILD_ONLY_CORE_LIBRARY)
add_subdirectory(Pdf4QtLibWidgets)
add_subdirectory(CodeGenerator)
add_subdirectory(JBIG2_Viewer)
add_subdirectory(PdfExampleGenerator)
add_subdirectory(PdfTool)
add_subdirectory(UnitTests)
add_subdirectory(Pdf4QtLibGui)
add_subdirectory(Pdf4QtEditorPlugins)
add_subdirectory(Pdf4QtEditor)
add_subdirectory(Pdf4QtViewer)
add_subdirectory(Pdf4QtPageMaster)
add_subdirectory(Pdf4QtDiff)
add_subdirectory(Pdf4QtLaunchPad)
add_subdirectory(WixInstaller)
endif()
message("CMAKE_PREFIX_PATH = " ${CMAKE_PREFIX_PATH})
message("CMAKE_TOOLCHAIN_FILE = " ${CMAKE_TOOLCHAIN_FILE})
install(FILES Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtDocDiff.desktop Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtDocPageOrganizer.desktop Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtViewerLite.desktop Desktop/io.github.JakubMelka.Pdf4qt.desktop DESTINATION share/applications)
install(FILES Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtDocDiff.svg Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtDocPageOrganizer.svg Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtViewerLite.svg Desktop/io.github.JakubMelka.Pdf4qt.svg DESTINATION share/icons/hicolor/scalable/apps)
install(FILES Desktop/io.github.JakubMelka.Pdf4qt.appdata.xml DESTINATION share/metainfo)
install(FILES Desktop/128x128/io.github.JakubMelka.Pdf4qt.Pdf4QtDocDiff.png Desktop/128x128/io.github.JakubMelka.Pdf4qt.Pdf4QtDocPageOrganizer.png Desktop/128x128/io.github.JakubMelka.Pdf4qt.Pdf4QtViewerLite.png Desktop/128x128/io.github.JakubMelka.Pdf4qt.png DESTINATION share/icons/hicolor/128x128/apps)
if(NOT PDF4QT_BUILD_ONLY_CORE_LIBRARY)
install(FILES Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtDiff.desktop
Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtPageMaster.desktop
Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtViewer.desktop
Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtEditor.desktop
Desktop/io.github.JakubMelka.Pdf4qt.desktop
DESTINATION ${PDF4QT_INSTALL_SHARE_DIR}/applications)
install(FILES Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtDiff.svg
Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtPageMaster.svg
Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtViewer.svg
Desktop/io.github.JakubMelka.Pdf4qt.Pdf4QtEditor.svg
Desktop/io.github.JakubMelka.Pdf4qt.svg
DESTINATION ${PDF4QT_INSTALL_SHARE_DIR}/icons/hicolor/scalable/apps)
install(FILES Desktop/io.github.JakubMelka.Pdf4qt.appdata.xml DESTINATION ${PDF4QT_INSTALL_SHARE_DIR}/metainfo)
install(FILES Desktop/128x128/io.github.JakubMelka.Pdf4qt.Pdf4QtDiff.png
Desktop/128x128/io.github.JakubMelka.Pdf4qt.Pdf4QtPageMaster.png
Desktop/128x128/io.github.JakubMelka.Pdf4qt.Pdf4QtViewer.png
Desktop/128x128/io.github.JakubMelka.Pdf4qt.Pdf4QtEditor.png
Desktop/128x128/io.github.JakubMelka.Pdf4qt.png
DESTINATION ${PDF4QT_INSTALL_SHARE_DIR}/icons/hicolor/128x128/apps)
configure_file(make-package.sh.in make-package.sh)
configure_file(make-package.sh.in make-package.sh)
endif()
if(PDF4QT_INSTALL_DEPENDENCIES)
if(PDF4QT_INSTALL_DEPENDENCIES AND NOT PDF4QT_BUILD_ONLY_CORE_LIBRARY)
install(DIRECTORY ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/
TYPE BIN
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/
FILES_MATCHING
PATTERN "*.dll"
PATTERN "*.so"
@ -119,14 +182,14 @@ if(PDF4QT_INSTALL_DEPENDENCIES)
if(PDF4QT_INSTALL_QT_DEPENDENCIES)
install(DIRECTORY ${PDF4QT_QT_ROOT}/bin/
RUNTIME DESTINATION bin/
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/
FILES_MATCHING
REGEX "(Qt6Core|Qt6Gui|Qt6PrintSupport|Qt6Svg|Qt6TextToSpeech|Qt6Widgets|Qt6Xml|Qt6OpenGL|Qt6OpenGLWidgets|Qt6Multimedia|Qt6Network)\\..*"
REGEX "(Qt6Core|Qt6Gui|Qt6PrintSupport|Qt6Svg|Qt6TextToSpeech|Qt6Widgets|Qt6Xml|Qt6Multimedia|Qt6Network)\\..*"
PATTERN "Debug" EXCLUDE
)
install(DIRECTORY ${PDF4QT_QT_ROOT}/plugins/platforms/
RUNTIME DESTINATION bin/platforms/
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/platforms/
FILES_MATCHING
PATTERN "qwindows.dll"
PATTERN "*.so"
@ -134,13 +197,13 @@ if(PDF4QT_INSTALL_DEPENDENCIES)
)
install(DIRECTORY ${PDF4QT_QT_ROOT}/plugins/iconengines/
RUNTIME DESTINATION bin/iconengines/
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/iconengines/
FILES_MATCHING
REGEX "qsvgicon\\..*"
)
install(DIRECTORY ${PDF4QT_QT_ROOT}/plugins/imageformats/
RUNTIME DESTINATION bin/imageformats/
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/imageformats/
FILES_MATCHING
PATTERN "*.dll"
PATTERN "*.so"
@ -149,7 +212,7 @@ if(PDF4QT_INSTALL_DEPENDENCIES)
)
install(DIRECTORY ${PDF4QT_QT_ROOT}/plugins/styles/
RUNTIME DESTINATION bin/styles/
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/styles/
FILES_MATCHING
PATTERN "*.dll"
PATTERN "*.so"
@ -158,7 +221,7 @@ if(PDF4QT_INSTALL_DEPENDENCIES)
)
install(DIRECTORY ${PDF4QT_QT_ROOT}/plugins/texttospeech/
RUNTIME DESTINATION bin/texttospeech/
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/texttospeech/
FILES_MATCHING
PATTERN "*.dll"
PATTERN "*.so"
@ -172,7 +235,7 @@ if(PDF4QT_INSTALL_DEPENDENCIES)
message(STATUS "MSVC Redistributable Package Path = ${MSVC_REDISTRIBUTABLES_PATH}")
install(DIRECTORY ${MSVC_REDISTRIBUTABLES_PATH}/
RUNTIME DESTINATION bin/
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/
FILES_MATCHING
PATTERN "*.dll"
)

View File

@ -1,4 +1,4 @@
# Copyright (C) 2022 Jakub Melka
# Copyright (C) 2022-2023 Jakub Melka
#
# This file is part of PDF4QT.
#
@ -17,14 +17,18 @@
add_executable(CodeGenerator
codegenerator.cpp
codegenerator.h
main.cpp
generatormainwindow.cpp
generatormainwindow.ui
generatormainwindow.h
generatormainwindow.ui
)
target_link_libraries(CodeGenerator PRIVATE Pdf4QtLib Qt6::Core Qt6::Widgets Qt6::Gui Qt6::Xml)
target_link_libraries(CodeGenerator PRIVATE Pdf4QtLibCore Qt6::Core Qt6::Widgets Qt6::Gui Qt6::Xml)
set_target_properties(CodeGenerator PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_INSTALL_LIB_DIR}
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_INSTALL_BIN_DIR}
)

View File

@ -22,7 +22,8 @@
int main(int argc, char *argv[])
{
qSetGlobalQHashSeed(0);
QHashSeed::globalSeed().setDeterministicGlobalSeed();
QApplication a(argc, argv);
GeneratorMainWindow w;
w.show();

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=PDF4QT Diff
Comment=Compare PDF documents
Exec=Pdf4QtDiff
Icon=io.github.JakubMelka.Pdf4qt.Pdf4QtDiff
Terminal=false
Categories=Office;
MimeType=application/pdf;

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,10 +0,0 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=PDF4QT DocDiff
Comment=Compare PDF documents
Exec=Pdf4QtDocDiff
Icon=io.github.JakubMelka.Pdf4qt.Pdf4QtDocDiff.svg
Terminal=false
Categories=Office
MimeType=application/pdf

View File

@ -1,10 +0,0 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=PDF4QT DocPage Organizer
Comment=Organize, merge, split, and duplicate pages in PDF files
Exec=Pdf4QtDocPageOrganizer
Icon=io.github.JakubMelka.Pdf4qt.Pdf4QtDocPageOrganizer.svg
Terminal=false
Categories=Office
MimeType=application/pdf

View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=PDF4QT Editor
Comment=Edit and modify PDF files
Exec=Pdf4QtEditor
Icon=io.github.JakubMelka.Pdf4qt.Pdf4QtEditor.svg
Terminal=false
Categories=Office;
MimeType=application/pdf;

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=PDF4QT PageMaster
Comment=Organize, merge, split, and duplicate pages in PDF files
Exec=Pdf4QtPageMaster
Icon=io.github.JakubMelka.Pdf4qt.Pdf4QtPageMaster
Terminal=false
Categories=Office;
MimeType=application/pdf;

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=PDF4QT Viewer
Comment=View and navigate PDF documents
Exec=Pdf4QtViewer
Icon=io.github.JakubMelka.Pdf4qt.Pdf4QtViewer
Terminal=false
Categories=Office;
MimeType=application/pdf;

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,10 +0,0 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=PDF4QT Viewer Lite
Comment=View and navigate PDF documents
Exec=Pdf4QtViewerLite
Icon=io.github.JakubMelka.Pdf4qt.Pdf4QtViewerLite.svg
Terminal=false
Categories=Office
MimeType=application/pdf

View File

@ -23,6 +23,8 @@
<content_rating type="oars-1.1"/>
<launchable type="desktop-id">io.github.JakubMelka.Pdf4qt.desktop</launchable>
<releases>
<release version="1.3.7" date="2024-01-10"/>
<release version="1.3.6" date="2023-11-24"/>
<release version="1.3.5" date="2023-09-08"/>
<release version="1.3.4" date="2023-08-03"/>
<release version="1.3.3" date="2023-04-22"/>

View File

@ -1,10 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=PDF4QT Viewer Profi
Comment=Edit and modify PDF files
Exec=Pdf4QtViewerProfi
Icon=io.github.JakubMelka.Pdf4qt.svg
Name=PDF4QT LaunchPad
Comment=Launch PDF applications
Exec=Pdf4QtLaunchPad
Icon=io.github.JakubMelka.Pdf4qt
Terminal=false
Categories=Office
MimeType=application/pdf
Categories=Office;
MimeType=application/pdf;

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -1,4 +1,4 @@
# Copyright (C) 2022 Jakub Melka
# Copyright (C) 2022-2023 Jakub Melka
#
# This file is part of PDF4QT.
#
@ -18,12 +18,15 @@
add_executable(JBIG2_VIEWER
mainwindow.ui
mainwindow.cpp
mainwindow.h
main.cpp
)
target_link_libraries(JBIG2_VIEWER PRIVATE Pdf4QtLib Qt6::Core Qt6::Widgets Qt6::Gui)
target_link_libraries(JBIG2_VIEWER PRIVATE Pdf4QtLibCore Qt6::Core Qt6::Widgets Qt6::Gui)
set_target_properties(JBIG2_VIEWER PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_INSTALL_LIB_DIR}
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_INSTALL_BIN_DIR}
)

49
Pdf4QtDiff/CMakeLists.txt Normal file
View File

@ -0,0 +1,49 @@
# Copyright (C) 2022-2024 Jakub Melka
#
# This file is part of PDF4QT.
#
# PDF4QT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# with the written consent of the copyright owner, any later version.
#
# PDF4QT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
add_executable(Pdf4QtDiff
aboutdialog.cpp
aboutdialog.h
differencesdockwidget.cpp
differencesdockwidget.h
main.cpp
mainwindow.cpp
mainwindow.h
settingsdockwidget.cpp
settingsdockwidget.h
utils.cpp
utils.h
aboutdialog.ui
differencesdockwidget.ui
mainwindow.ui
settingsdockwidget.ui
resources.qrc
icon.rc
app.qrc
settings.h
)
target_link_libraries(Pdf4QtDiff PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(Pdf4QtDiff PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_INSTALL_LIB_DIR}
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_INSTALL_BIN_DIR}
)
install(TARGETS Pdf4QtDiff RUNTIME DESTINATION ${PDF4QT_INSTALL_BIN_DIR} LIBRARY DESTINATION ${PDF4QT_INSTALL_LIB_DIR})

View File

@ -0,0 +1,64 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include "pdfutils.h"
#include "pdfwidgetutils.h"
namespace pdfdiff
{
PDFAboutDialog::PDFAboutDialog(QWidget* parent) :
QDialog(parent),
ui(new Ui::PDFAboutDialog)
{
ui->setupUi(this);
QString html = ui->copyrightLabel->text();
html.replace("PdfForQtViewer", QString("%1 %2").arg(QApplication::applicationDisplayName(), QApplication::applicationVersion()));
ui->copyrightLabel->setText(html);
std::vector<pdf::PDFDependentLibraryInfo> infos = pdf::PDFDependentLibraryInfo::getLibraryInfo();
ui->tableWidget->setColumnCount(4);
ui->tableWidget->setRowCount(static_cast<int>(infos.size()));
ui->tableWidget->setHorizontalHeaderLabels(QStringList() << tr("Library") << tr("Version") << tr("License") << tr("URL"));
ui->tableWidget->setEditTriggers(QTableWidget::NoEditTriggers);
ui->tableWidget->setSelectionMode(QTableView::SingleSelection);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
for (int i = 0; i < infos.size(); ++i)
{
const pdf::PDFDependentLibraryInfo& info = infos[i];
ui->tableWidget->setItem(i, 0, new QTableWidgetItem(info.library));
ui->tableWidget->setItem(i, 1, new QTableWidgetItem(info.version));
ui->tableWidget->setItem(i, 2, new QTableWidgetItem(info.license));
ui->tableWidget->setItem(i, 3, new QTableWidgetItem(info.url));
}
pdf::PDFWidgetUtils::scaleWidget(this, QSize(750, 600));
pdf::PDFWidgetUtils::style(this);
}
PDFAboutDialog::~PDFAboutDialog()
{
delete ui;
}
} // namespace pdfdiff

45
Pdf4QtDiff/aboutdialog.h Normal file
View File

@ -0,0 +1,45 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDIFF_PDFABOUTDIALOG_H
#define PDFDIFF_PDFABOUTDIALOG_H
#include <QDialog>
namespace Ui
{
class PDFAboutDialog;
}
namespace pdfdiff
{
class PDFAboutDialog : public QDialog
{
Q_OBJECT
public:
explicit PDFAboutDialog(QWidget* parent);
virtual ~PDFAboutDialog() override;
private:
Ui::PDFAboutDialog* ui;
};
} // namespace pdfdiff
#endif // PDFDIFF_PDFABOUTDIALOG_H

272
Pdf4QtDiff/aboutdialog.ui Normal file
View File

@ -0,0 +1,272 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PDFAboutDialog</class>
<widget class="QDialog" name="PDFAboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>600</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>900</width>
<height>600</height>
</size>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="copyrightLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;PdfForQtViewer&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Copyright 2018-2024 Jakub Melka. All rights reserved.&lt;/p&gt;&lt;p&gt;THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEdit">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; GNU LESSER GENERAL PUBLIC LICENSE&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Version 3, 29 June 2007&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Copyright (C) 2007 Free Software Foundation, Inc. &amp;lt;https://fsf.org/&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Everyone is permitted to copy and distribute verbatim copies&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; of this license document, but changing it is not allowed.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; This version of the GNU Lesser General Public License incorporates&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;the terms and conditions of version 3 of the GNU General Public&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;License, supplemented by the additional permissions listed below.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 0. Additional Definitions.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; As used herein, &amp;quot;this License&amp;quot; refers to version 3 of the GNU Lesser&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;General Public License, and the &amp;quot;GNU GPL&amp;quot; refers to version 3 of the GNU&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;General Public License.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; &amp;quot;The Library&amp;quot; refers to a covered work governed by this License,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;other than an Application or a Combined Work as defined below.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; An &amp;quot;Application&amp;quot; is any work that makes use of an interface provided&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;by the Library, but which is not otherwise based on the Library.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;Defining a subclass of a class defined by the Library is deemed a mode&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;of using an interface provided by the Library.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; A &amp;quot;Combined Work&amp;quot; is a work produced by combining or linking an&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;Application with the Library. The particular version of the Library&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;with which the Combined Work was made is also called the &amp;quot;Linked&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;Version&amp;quot;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; The &amp;quot;Minimal Corresponding Source&amp;quot; for a Combined Work means the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;Corresponding Source for the Combined Work, excluding any source code&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;for portions of the Combined Work that, considered in isolation, are&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;based on the Application, and not on the Linked Version.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; The &amp;quot;Corresponding Application Code&amp;quot; for a Combined Work means the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;object code and/or source code for the Application, including any data&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;and utility programs needed for reproducing the Combined Work from the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;Application, but excluding the System Libraries of the Combined Work.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 1. Exception to Section 3 of the GNU GPL.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; You may convey a covered work under sections 3 and 4 of this License&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;without being bound by section 3 of the GNU GPL.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 2. Conveying Modified Versions.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; If you modify a copy of the Library, and, in your modifications, a&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;facility refers to a function or data to be supplied by an Application&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;that uses the facility (other than as an argument passed when the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;facility is invoked), then you may convey a copy of the modified&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;version:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; a) under this License, provided that you make a good faith effort to&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; ensure that, in the event an Application does not supply the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; function or data, the facility still operates, and performs&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; whatever part of its purpose remains meaningful, or&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; b) under the GNU GPL, with none of the additional permissions of&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; this License applicable to that copy.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 3. Object Code Incorporating Material from Library Header Files.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; The object code form of an Application may incorporate material from&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;a header file that is part of the Library. You may convey such object&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;code under terms of your choice, provided that, if the incorporated&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;material is not limited to numerical parameters, data structure&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;layouts and accessors, or small macros, inline functions and templates&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;(ten or fewer lines in length), you do both of the following:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; a) Give prominent notice with each copy of the object code that the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Library is used in it and that the Library and its use are&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; covered by this License.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; b) Accompany the object code with a copy of the GNU GPL and this license&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; document.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 4. Combined Works.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; You may convey a Combined Work under terms of your choice that,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;taken together, effectively do not restrict modification of the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;portions of the Library contained in the Combined Work and reverse&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;engineering for debugging such modifications, if you also do each of&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;the following:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; a) Give prominent notice with each copy of the Combined Work that&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; the Library is used in it and that the Library and its use are&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; covered by this License.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; b) Accompany the Combined Work with a copy of the GNU GPL and this license&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; document.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; c) For a Combined Work that displays copyright notices during&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; execution, include the copyright notice for the Library among&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; these notices, as well as a reference directing the user to the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; copies of the GNU GPL and this license document.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; d) Do one of the following:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 0) Convey the Minimal Corresponding Source under the terms of this&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; License, and the Corresponding Application Code in a form&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; suitable for, and under terms that permit, the user to&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; recombine or relink the Application with a modified version of&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; the Linked Version to produce a modified Combined Work, in the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; manner specified by section 6 of the GNU GPL for conveying&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Corresponding Source.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 1) Use a suitable shared library mechanism for linking with the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Library. A suitable mechanism is one that (a) uses at run time&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; a copy of the Library already present on the user's computer&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; system, and (b) will operate properly with a modified version&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; of the Library that is interface-compatible with the Linked&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Version.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; e) Provide Installation Information, but only if you would otherwise&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; be required to provide such information under section 6 of the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; GNU GPL, and only to the extent that such information is&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; necessary to install and execute a modified version of the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Combined Work produced by recombining or relinking the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Application with a modified version of the Linked Version. (If&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; you use option 4d0, the Installation Information must accompany&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; the Minimal Corresponding Source and Corresponding Application&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Code. If you use option 4d1, you must provide the Installation&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Information in the manner specified by section 6 of the GNU GPL&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; for conveying Corresponding Source.)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 5. Combined Libraries.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; You may place library facilities that are a work based on the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;Library side by side in a single library together with other library&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;facilities that are not Applications and are not covered by this&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;License, and convey such a combined library under terms of your&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;choice, if you do both of the following:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; a) Accompany the combined library with a copy of the same work based&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; on the Library, uncombined with any other library facilities,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; conveyed under the terms of this License.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; b) Give prominent notice with the combined library that part of it&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; is a work based on the Library, and explaining where to find the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; accompanying uncombined form of the same work.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; 6. Revised Versions of the GNU Lesser General Public License.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; The Free Software Foundation may publish revised and/or new versions&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;of the GNU Lesser General Public License from time to time. Such new&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;versions will be similar in spirit to the present version, but may&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;differ in detail to address new problems or concerns.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; Each version is given a distinguishing version number. If the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;Library as you received it specifies that a certain numbered version&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;of the GNU Lesser General Public License &amp;quot;or any later version&amp;quot;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;applies to it, you have the option of following the terms and&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;conditions either of that published version or of any later version&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;published by the Free Software Foundation. If the Library as you&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;received it does not specify a version number of the GNU Lesser&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;General Public License, you may choose any version of the GNU Lesser&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;General Public License ever published by the Free Software Foundation.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt; If the Library as you received it specifies that a proxy can decide&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;whether future versions of the GNU Lesser General Public License shall&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;apply, that proxy's public statement of acceptance of any version is&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;permanent authorization for you to choose that version for the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;Library.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="usedLibrariesLabel">
<property name="text">
<string>Used libraries</string>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="tableWidget"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PDFAboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PDFAboutDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

5
Pdf4QtDiff/app.qrc Normal file
View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>app-icon.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,307 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "differencesdockwidget.h"
#include "ui_differencesdockwidget.h"
#include "pdfdiff.h"
#include "pdfwidgetutils.h"
#include <QPixmap>
#include <QPainter>
#include <QTreeWidgetItem>
namespace pdfdiff
{
DifferenceItemDelegate::DifferenceItemDelegate(QObject* parent) :
BaseClass(parent)
{
}
void DifferenceItemDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
BaseClass::paint(painter, option, index);
}
QSize DifferenceItemDelegate::sizeHint(const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
QStyleOptionViewItem adjustedOption = option;
if (!option.rect.isValid())
{
// Jakub Melka: Why this? We need to use text wrapping. Unfortunately,
// standard delegate needs correct text rectangle (at least rectangle width),
// for word wrap calculation. So we must manually calculate rectangle width.
// Of course, we cant use visualRect of the tree widget, because of cyclical
// dependence.
const QTreeWidget* treeWidget = qobject_cast<const QTreeWidget*>(option.widget);
int xOffset = treeWidget->columnViewportPosition(index.column());
int height = option.fontMetrics.lineSpacing();
int yOffset = 0;
int width = treeWidget->columnWidth(index.column());
int level = treeWidget->rootIsDecorated() ? 1 : 0;
QModelIndex currentIndex = index.parent();
while (currentIndex.isValid())
{
++level;
currentIndex = currentIndex.parent();
}
xOffset += level * treeWidget->indentation();
adjustedOption.rect = QRect(xOffset, yOffset, width - xOffset, height);
}
return BaseClass::sizeHint(adjustedOption, index);
}
DifferencesDockWidget::DifferencesDockWidget(QWidget* parent,
pdf::PDFDiffResult* unfilteredDiffResult,
pdf::PDFDiffResult* diffResult,
pdf::PDFDiffResultNavigator* diffNavigator,
Settings* settings) :
QDockWidget(parent),
ui(new Ui::DifferencesDockWidget),
m_unfilteredDiffResult(unfilteredDiffResult),
m_diffResult(diffResult),
m_diffNavigator(diffNavigator),
m_settings(settings),
m_disableChangeSelectedResultIndex(false)
{
ui->setupUi(this);
ui->differencesTreeWidget->setItemDelegate(new DifferenceItemDelegate(this));
ui->differencesTreeWidget->setIconSize(pdf::PDFWidgetUtils::scaleDPI(ui->differencesTreeWidget, QSize(16, 16)));
connect(diffNavigator, &pdf::PDFDiffResultNavigator::selectionChanged, this, &DifferencesDockWidget::onSelectionChanged);
connect(ui->differencesTreeWidget, &QTreeWidget::currentItemChanged, this, &DifferencesDockWidget::onCurrentItemChanged);
toggleViewAction()->setText(tr("Differen&ces"));
setMinimumWidth(pdf::PDFWidgetUtils::scaleDPI_x(this, 120));
}
DifferencesDockWidget::~DifferencesDockWidget()
{
delete ui;
}
QColor DifferencesDockWidget::getColorForIndex(size_t index) const
{
QColor color;
const size_t resultIndex = index;
if (m_diffResult->isReplaceDifference(resultIndex))
{
color = m_settings->colorReplaced;
}
else if (m_diffResult->isRemoveDifference(resultIndex))
{
color = m_settings->colorRemoved;
}
else if (m_diffResult->isAddDifference(resultIndex))
{
color = m_settings->colorAdded;
}
else if (m_diffResult->isPageMoveDifference(resultIndex))
{
color = m_settings->colorPageMove;
}
return color;
}
QModelIndex DifferencesDockWidget::findResultIndex(size_t index) const
{
QAbstractItemModel* model = ui->differencesTreeWidget->model();
const int count = ui->differencesTreeWidget->topLevelItemCount();
for (int i = 0; i < count; ++i)
{
QModelIndex parentIndex = model->index(i, 0);
if (parentIndex.isValid())
{
const int childCount = model->rowCount(parentIndex);
for (int j = 0; j < childCount; ++j)
{
QModelIndex childIndex = model->index(j, 0, parentIndex);
QVariant childUserData = childIndex.data(Qt::UserRole);
if (childUserData.isValid())
{
if (childUserData.toULongLong() == index)
{
return childIndex;
}
}
}
}
}
return QModelIndex();
}
void DifferencesDockWidget::update()
{
ui->differencesTreeWidget->clear();
QList<QTreeWidgetItem*> topItems;
QLocale locale;
if (m_diffResult && !m_diffResult->isSame())
{
std::map<QRgb, QIcon> icons;
auto getIcon = [this, &icons](QColor color)
{
auto it = icons.find(color.rgb());
if (it == icons.end())
{
QPixmap pixmap(ui->differencesTreeWidget->iconSize());
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setPen(Qt::NoPen);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(QBrush(color));
painter.drawEllipse(0, 0, pixmap.width(), pixmap.height());
painter.end();
QIcon icon(pixmap);
it = icons.insert(std::make_pair(color.rgb(), std::move(icon))).first;
}
return it->second;
};
const size_t differenceCount = m_diffResult->getDifferencesCount();
const size_t unfilteredDifferenceCount = m_unfilteredDiffResult->getDifferencesCount();
const size_t hiddenDifferences = unfilteredDifferenceCount - differenceCount;
if (hiddenDifferences > 0)
{
ui->infoTextLabel->setText(tr("%1 Differences (+%2 hidden)").arg(differenceCount).arg(hiddenDifferences));
}
else
{
ui->infoTextLabel->setText(tr("%1 Differences").arg(differenceCount));
}
pdf::PDFInteger lastLeftPageIndex = -1;
pdf::PDFInteger lastRightPageIndex = -1;
for (size_t i = 0; i < differenceCount; ++i)
{
pdf::PDFInteger pageIndexLeft = m_diffResult->getLeftPage(i);
pdf::PDFInteger pageIndexRight = m_diffResult->getRightPage(i);
if (lastLeftPageIndex != pageIndexLeft ||
lastRightPageIndex != pageIndexRight ||
topItems.empty())
{
// Create new top level item
QStringList captionParts;
captionParts << QString("#%1:").arg(topItems.size() + 1);
if (pageIndexLeft == pageIndexRight)
{
captionParts << tr("Page %1").arg(locale.toString(pageIndexLeft + 1));
}
else
{
if (pageIndexLeft != -1)
{
captionParts << tr("Left %1").arg(locale.toString(pageIndexLeft + 1));
}
if (pageIndexRight != -1)
{
captionParts << tr("Right %1").arg(locale.toString(pageIndexRight + 1));
}
}
QTreeWidgetItem* item = new QTreeWidgetItem(QStringList() << captionParts.join(" "));
topItems << item;
lastLeftPageIndex = pageIndexLeft;
lastRightPageIndex = pageIndexRight;
}
Q_ASSERT(!topItems.isEmpty());
QTreeWidgetItem* parent = topItems.back();
QTreeWidgetItem* item = new QTreeWidgetItem(parent, QStringList() << m_diffResult->getMessage(i));
item->setData(0, Qt::UserRole, QVariant(static_cast<qint64>(i)));
QColor color = getColorForIndex(i);
if (color.isValid())
{
item->setData(0, Qt::DecorationRole, getIcon(color));
}
}
}
else
{
ui->infoTextLabel->setText(tr("No Differences Found!"));
}
ui->differencesTreeWidget->addTopLevelItems(topItems);
ui->differencesTreeWidget->expandAll();
}
void DifferencesDockWidget::onSelectionChanged(size_t currentIndex)
{
if (m_disableChangeSelectedResultIndex)
{
return;
}
pdf::PDFTemporaryValueChange guard(&m_disableChangeSelectedResultIndex, true);
QModelIndex index = findResultIndex(currentIndex);
if (index.isValid())
{
ui->differencesTreeWidget->scrollTo(index);
ui->differencesTreeWidget->setCurrentIndex(index);
}
}
void DifferencesDockWidget::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
{
Q_UNUSED(previous);
if (m_disableChangeSelectedResultIndex || !current)
{
return;
}
pdf::PDFTemporaryValueChange guard(&m_disableChangeSelectedResultIndex, true);
QVariant childUserData = current->data(0, Qt::UserRole);
if (childUserData.isValid())
{
m_diffNavigator->select(childUserData.toULongLong());
}
}
} // namespace pdfdiff

View File

@ -0,0 +1,89 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDIFF_DIFFERENCESDOCKWIDGET_H
#define PDFDIFF_DIFFERENCESDOCKWIDGET_H
#include "settings.h"
#include <QDockWidget>
#include <QItemDelegate>
namespace Ui
{
class DifferencesDockWidget;
}
class QTreeWidgetItem;
namespace pdf
{
class PDFDiffResult;
class PDFDiffResultNavigator;
}
namespace pdfdiff
{
class DifferenceItemDelegate : public QItemDelegate
{
Q_OBJECT
private:
using BaseClass = QItemDelegate;
public:
DifferenceItemDelegate(QObject* parent);
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
};
class DifferencesDockWidget : public QDockWidget
{
Q_OBJECT
public:
explicit DifferencesDockWidget(QWidget* parent,
pdf::PDFDiffResult* unfilteredDiffResult,
pdf::PDFDiffResult* diffResult,
pdf::PDFDiffResultNavigator* diffNavigator,
Settings* settings);
virtual ~DifferencesDockWidget() override;
void update();
private slots:
void onSelectionChanged(size_t currentIndex);
void onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
private:
Ui::DifferencesDockWidget* ui;
QColor getColorForIndex(size_t index) const;
QModelIndex findResultIndex(size_t index) const;
pdf::PDFDiffResult* m_unfilteredDiffResult;
pdf::PDFDiffResult* m_diffResult;
pdf::PDFDiffResultNavigator* m_diffNavigator;
Settings* m_settings;
bool m_disableChangeSelectedResultIndex;
};
} // namespace pdfdiff
#endif // PDFDIFF_DIFFERENCESDOCKWIDGET_H

48
Pdf4QtDiff/main.cpp Normal file
View File

@ -0,0 +1,48 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdfconstants.h"
#include "mainwindow.h"
#include <QApplication>
#include <QCommandLineParser>
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
QApplication application(argc, argv);
QCoreApplication::setOrganizationName("MelkaJ");
QCoreApplication::setApplicationName("PDF4QT Diff");
QCoreApplication::setApplicationVersion(pdf::PDF_LIBRARY_VERSION);
QApplication::setApplicationDisplayName(QApplication::translate("Application", "PDF4QT Diff"));
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::applicationName());
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("file1", "The PDF file to be compared.");
parser.addPositionalArgument("file2", "The PDF file to be compared.");
parser.process(application);
QIcon appIcon(":/app-icon.svg");
QApplication::setWindowIcon(appIcon);
pdfdiff::MainWindow mainWindow(nullptr);
mainWindow.show();
return application.exec();
}

899
Pdf4QtDiff/mainwindow.cpp Normal file
View File

@ -0,0 +1,899 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "aboutdialog.h"
#include "differencesdockwidget.h"
#include "settingsdockwidget.h"
#include "pdfwidgetutils.h"
#include "pdfdocumentreader.h"
#include "pdfdrawspacecontroller.h"
#include "pdfdocumentmanipulator.h"
#include "pdfdocumentbuilder.h"
#include "pdfdocumentwriter.h"
#include "pdfwidgetutils.h"
#include <QToolBar>
#include <QDesktopServices>
#include <QMessageBox>
#include <QInputDialog>
#include <QFileDialog>
#include <QVBoxLayout>
#include <QActionGroup>
#include <QScreen>
#include <QSettings>
namespace pdfdiff
{
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_progress(new pdf::PDFProgress(this)),
#ifdef WIN_TASKBAR_BUTTON
m_taskbarButton(new QWinTaskbarButton(this)),
m_progressTaskbarIndicator(nullptr),
#endif
m_cmsManager(nullptr),
m_pdfWidget(nullptr),
m_settingsDockWidget(nullptr),
m_differencesDockWidget(nullptr),
m_optionalContentActivity(nullptr),
m_diff(nullptr),
m_isChangingProgressStep(false),
m_dontDisplayErrorMessage(false),
m_diffNavigator(nullptr),
m_drawInterface(&m_settings, &m_documentMapper, &m_filteredDiffResult)
{
ui->setupUi(this);
setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600)));
// Initialize task bar progress
#ifdef WIN_TASKBAR_BUTTON
m_progressTaskbarIndicator = m_taskbarButton->progress();
#endif
m_settingsDockWidget = new SettingsDockWidget(&m_settings, this);
addDockWidget(Qt::LeftDockWidgetArea, m_settingsDockWidget);;
connect(m_settingsDockWidget, &SettingsDockWidget::colorsChanged, this, &MainWindow::onColorsChanged);
connect(m_settingsDockWidget, &SettingsDockWidget::transparencySliderChanged, this, &MainWindow::updateOverlayTransparency);
m_differencesDockWidget = new DifferencesDockWidget(this, &m_diffResult, &m_filteredDiffResult, &m_diffNavigator, &m_settings);
addDockWidget(Qt::LeftDockWidgetArea, m_differencesDockWidget);
ui->documentFrame->setLayout(new QVBoxLayout);
m_cmsManager = new pdf::PDFCMSManager(this);
m_pdfWidget = new pdf::PDFWidget(m_cmsManager, pdf::RendererEngine::QPainter, ui->documentFrame);
m_pdfWidget->getDrawWidgetProxy()->setProgress(m_progress);
ui->documentFrame->layout()->addWidget(m_pdfWidget);
m_pdfWidget->getDrawWidgetProxy()->registerDrawInterface(&m_drawInterface);
ui->menuView->addSeparator();
ui->menuView->addAction(m_settingsDockWidget->toggleViewAction());
ui->menuView->addAction(m_differencesDockWidget->toggleViewAction());
ui->actionGet_Source->setData(int(Operation::GetSource));
ui->actionBecomeASponsor->setData(int(Operation::BecomeSponsor));
ui->actionAbout->setData(int(Operation::About));
ui->actionOpen_Left->setData(int(Operation::OpenLeft));
ui->actionOpen_Right->setData(int(Operation::OpenRight));
ui->actionCompare->setData(int(Operation::Compare));
ui->actionClose->setData(int(Operation::Close));
ui->actionPrevious_Difference->setData(int(Operation::PreviousDifference));
ui->actionNext_Difference->setData(int(Operation::NextDifference));
ui->actionCreate_Compare_Report->setData(int(Operation::CreateCompareReport));
ui->actionFilter_Text->setData(int(Operation::FilterText));
ui->actionFilter_Vector_Graphics->setData(int(Operation::FilterVectorGraphics));
ui->actionFilter_Images->setData(int(Operation::FilterImages));
ui->actionFilter_Shading->setData(int(Operation::FilterShading));
ui->actionFilter_Page_Movement->setData(int(Operation::FilterPageMovement));
ui->actionView_Differences->setData(int(Operation::ViewDifferences));
ui->actionView_Left->setData(int(Operation::ViewLeft));
ui->actionView_Right->setData(int(Operation::ViewRight));
ui->actionView_Overlay->setData(int(Operation::ViewOverlay));
ui->actionShow_Pages_with_Differences->setData(int(Operation::ShowPageswithDifferences));
ui->actionSave_Differences_to_XML->setData(int(Operation::SaveDifferencesToXML));
ui->actionDisplay_Differences->setData(int(Operation::DisplayDifferences));
ui->actionDisplay_Markers->setData(int(Operation::DisplayMarkers));
ui->actionSynchronize_View_with_Differences->setChecked(true);
QActionGroup* actionGroup = new QActionGroup(this);
actionGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive);
actionGroup->addAction(ui->actionView_Differences);
actionGroup->addAction(ui->actionView_Left);
actionGroup->addAction(ui->actionView_Right);
actionGroup->addAction(ui->actionView_Overlay);
ui->actionView_Differences->setChecked(true);
QToolBar* mainToolbar = addToolBar(tr("&Main"));
mainToolbar->setObjectName("main_toolbar");
mainToolbar->addActions({ ui->actionOpen_Left, ui->actionOpen_Right });
mainToolbar->addSeparator();
mainToolbar->addAction(ui->actionCompare);
mainToolbar->addAction(ui->actionCreate_Compare_Report);
mainToolbar->addAction(ui->actionSave_Differences_to_XML);
QToolBar* differencesToolbar = addToolBar(tr("&Differences"));
differencesToolbar->setObjectName("differences_toolbar");
differencesToolbar->addActions({ ui->actionPrevious_Difference, ui->actionNext_Difference });
QToolBar* viewToolbar = addToolBar(tr("&View"));
viewToolbar->setObjectName("view_toolbar");
viewToolbar->addActions({ ui->actionView_Differences, ui->actionView_Left, ui->actionView_Right, ui->actionView_Overlay });
viewToolbar->addSeparator();
viewToolbar->addActions({ ui->actionShow_Pages_with_Differences, ui->actionSynchronize_View_with_Differences });
viewToolbar->addSeparator();
viewToolbar->addActions({ ui->actionFilter_Text, ui->actionFilter_Vector_Graphics, ui->actionFilter_Images, ui->actionFilter_Shading, ui->actionFilter_Page_Movement });
QSize iconSize = pdf::PDFWidgetUtils::scaleDPI(this, QSize(24, 24));
auto toolbars = findChildren<QToolBar*>();
for (QToolBar* toolbar : toolbars)
{
toolbar->setIconSize(iconSize);
ui->menuToolbars->addAction(toolbar->toggleViewAction());
}
connect(&m_mapper, &QSignalMapper::mappedInt, this, &MainWindow::onMappedActionTriggered);
QList<QAction*> actions = findChildren<QAction*>();
for (QAction* action : actions)
{
QVariant actionData = action->data();
if (actionData.isValid())
{
connect(action, &QAction::triggered, &m_mapper, QOverload<>::of(&QSignalMapper::map));
m_mapper.setMapping(action, actionData.toInt());
}
}
if (pdf::PDFWidgetUtils::isDarkTheme())
{
pdf::PDFWidgetUtils::convertActionsForDarkTheme(actions, iconSize, qGuiApp->devicePixelRatio());
}
connect(m_progress, &pdf::PDFProgress::progressStarted, this, &MainWindow::onProgressStarted);
connect(m_progress, &pdf::PDFProgress::progressStep, this, &MainWindow::onProgressStep);
connect(m_progress, &pdf::PDFProgress::progressFinished, this, &MainWindow::onProgressFinished);
m_diff.setProgress(m_progress);
m_diff.setOption(pdf::PDFDiff::Asynchronous, true);
connect(&m_diff, &pdf::PDFDiff::comparationFinished, this, &MainWindow::onComparationFinished);
m_diff.setLeftDocument(&m_leftDocument);
m_diff.setRightDocument(&m_rightDocument);
m_diffNavigator.setResult(&m_filteredDiffResult);
connect(&m_diffNavigator, &pdf::PDFDiffResultNavigator::selectionChanged, this, &MainWindow::onSelectionChanged);
loadSettings();
updateAll(false);
updateOverlayTransparency();
#ifndef NDEBUG
pdf::PDFWidgetUtils::checkMenuAccessibility(this);
#endif
}
MainWindow::~MainWindow()
{
saveSettings();
delete ui;
}
void MainWindow::showEvent(QShowEvent* event)
{
Q_UNUSED(event);
#ifdef WIN_TASKBAR_BUTTON
m_taskbarButton->setWindow(windowHandle());
#endif
}
void MainWindow::closeEvent(QCloseEvent* event)
{
BaseClass::closeEvent(event);
m_diff.stop();
}
void MainWindow::onMappedActionTriggered(int actionId)
{
performOperation(static_cast<Operation>(actionId));
}
void MainWindow::onComparationFinished()
{
clear(false, false);
m_diffResult = m_diff.getResult();
if (!m_dontDisplayErrorMessage)
{
if (!m_diffResult.getResult())
{
QMessageBox::critical(this, tr("Error"), m_diffResult.getResult().getErrorMessage());
}
if (m_diffResult.isSame())
{
QMessageBox::information(this, tr("Info"), tr("No differences found between the compared documents."), QMessageBox::Ok);
}
}
// Create merged document
pdf::PDFDocumentManipulator manipulator;
manipulator.setOutlineMode(pdf::PDFDocumentManipulator::OutlineMode::NoOutline);
manipulator.addDocument(1, &m_leftDocument);
manipulator.addDocument(2, &m_rightDocument);
pdf::PDFDocumentManipulator::AssembledPages assembledPages1 = pdf::PDFDocumentManipulator::createAllDocumentPages(1, &m_leftDocument);
pdf::PDFDocumentManipulator::AssembledPages assembledPages2 = pdf::PDFDocumentManipulator::createAllDocumentPages(2, &m_rightDocument);
assembledPages1.insert(assembledPages1.end(), std::make_move_iterator(assembledPages2.begin()), std::make_move_iterator(assembledPages2.end()));
if (manipulator.assemble(assembledPages1))
{
m_combinedDocument = manipulator.takeAssembledDocument();
}
else
{
m_combinedDocument = pdf::PDFDocument();
}
updateAll(true);
}
void MainWindow::onColorsChanged()
{
updateFilteredResult();
m_pdfWidget->update();
}
void MainWindow::updateActions()
{
QList<QAction*> actions = findChildren<QAction*>();
for (QAction* action : actions)
{
QVariant actionData = action->data();
if (actionData.isValid())
{
bool canPerformAction = canPerformOperation(static_cast<Operation>(actionData.toInt()));
action->setEnabled(canPerformAction);
if (!canPerformAction && action->isCheckable())
{
action->setChecked(false);
}
}
}
}
void MainWindow::onSelectionChanged(size_t currentIndex)
{
if (ui->actionSynchronize_View_with_Differences->isChecked())
{
pdf::PDFInteger destinationPage = -1;
if (destinationPage == -1)
{
pdf::PDFInteger leftPageIndex = m_filteredDiffResult.getLeftPage(currentIndex);
if (leftPageIndex != -1)
{
destinationPage = m_documentMapper.getPageIndexFromLeftPageIndex(leftPageIndex);
}
}
if (destinationPage == -1)
{
pdf::PDFInteger rightPageIndex = m_filteredDiffResult.getRightPage(currentIndex);
if (rightPageIndex != -1)
{
destinationPage = m_documentMapper.getPageIndexFromRightPageIndex(rightPageIndex);
}
}
if (destinationPage != -1)
{
m_pdfWidget->getDrawWidgetProxy()->goToPage(destinationPage);
}
}
updateActions();
}
void MainWindow::loadSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.beginGroup("MainWindow");
QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
if (geometry.isEmpty())
{
QRect availableGeometry = QApplication::primaryScreen()->availableGeometry();
QRect windowRect(0, 0, availableGeometry.width() / 2, availableGeometry.height() / 2);
windowRect = windowRect.translated(availableGeometry.center() - windowRect.center());
setGeometry(windowRect);
}
else
{
restoreGeometry(geometry);
}
QByteArray state = settings.value("windowState", QByteArray()).toByteArray();
if (!state.isEmpty())
{
restoreState(state);
}
settings.endGroup();
settings.beginGroup("Settings");
m_settings.directory = settings.value("directory").toString();
m_settings.colorPageMove = settings.value("colorPageMove", m_settings.colorPageMove).value<QColor>();
m_settings.colorAdded = settings.value("colorAdded", m_settings.colorAdded).value<QColor>();
m_settings.colorRemoved = settings.value("colorRemoved", m_settings.colorRemoved).value<QColor>();
m_settings.colorReplaced = settings.value("colorReplaced", m_settings.colorReplaced).value<QColor>();
m_settings.displayDifferences = settings.value("displayDifferences", m_settings.displayDifferences).toBool();
m_settings.displayMarkers = settings.value("displayMarkers", m_settings.displayDifferences).toBool();
settings.endGroup();
settings.beginGroup("Compare");
m_settingsDockWidget->setCompareTextsAsVectorGraphics(settings.value("compareTextsAsVectorGraphics", false).toBool());
m_settingsDockWidget->setCompareTextCharactersInsteadOfWords(settings.value("compareTextCharactersInsteadOfWords", false).toBool());
settings.endGroup();
ui->actionDisplay_Differences->setChecked(m_settings.displayDifferences);
ui->actionDisplay_Markers->setChecked(m_settings.displayMarkers);
m_settingsDockWidget->loadColors();
}
void MainWindow::saveSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.beginGroup("MainWindow");
settings.setValue("geometry", saveGeometry());
settings.setValue("windowState", saveState());
settings.endGroup();
settings.beginGroup("Settings");
settings.setValue("directory", m_settings.directory);
settings.setValue("colorPageMove", m_settings.colorPageMove);
settings.setValue("colorAdded", m_settings.colorAdded);
settings.setValue("colorRemoved", m_settings.colorRemoved);
settings.setValue("colorReplaced", m_settings.colorReplaced);
settings.setValue("displayDifferences", m_settings.displayDifferences);
settings.setValue("displayMarkers", m_settings.displayMarkers);
settings.endGroup();
settings.beginGroup("Compare");
settings.setValue("compareTextsAsVectorGraphics", m_settingsDockWidget->isCompareTextAsVectorGraphics());
settings.setValue("compareTextCharactersInsteadOfWords", m_settingsDockWidget->isCompareTextCharactersInsteadOfWords());
settings.endGroup();
}
bool MainWindow::canPerformOperation(Operation operation) const
{
switch (operation)
{
case Operation::OpenLeft:
case Operation::OpenRight:
case Operation::Compare:
case Operation::Close:
case Operation::GetSource:
case Operation::BecomeSponsor:
case Operation::About:
return true;
case Operation::ViewDifferences:
case Operation::ViewLeft:
case Operation::ViewRight:
case Operation::ViewOverlay:
return true; // Allow always to change a view
case Operation::FilterText:
return m_diffResult.hasTextDifferences();
case Operation::FilterVectorGraphics:
return m_diffResult.hasVectorGraphicsDifferences();
case Operation::FilterImages:
return m_diffResult.hasImageDifferences();
case Operation::FilterShading:
return m_diffResult.hasShadingDifferences();
case Operation::FilterPageMovement:
return m_diffResult.hasPageMoveDifferences();
case Operation::PreviousDifference:
return m_diffNavigator.canGoPrevious();
case Operation::NextDifference:
return m_diffNavigator.canGoNext();
case Operation::CreateCompareReport:
case Operation::SaveDifferencesToXML:
return m_filteredDiffResult.isChanged();
case Operation::ShowPageswithDifferences:
return m_diffResult.isChanged();
case Operation::DisplayDifferences:
case Operation::DisplayMarkers:
return true;
default:
Q_ASSERT(false);
break;
}
return false;
}
void MainWindow::performOperation(Operation operation)
{
switch (operation)
{
case Operation::OpenLeft:
{
pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true);
m_diff.stop();
std::optional<pdf::PDFDocument> document = openDocument();
if (document)
{
clear(true, false);
m_leftDocument = std::move(*document);
const size_t pageCount = m_leftDocument.getCatalog()->getPageCount();
if (pageCount > 1)
{
m_settingsDockWidget->getLeftPageSelectionEdit()->setText(QString("1-%2").arg(pageCount));
}
else if (pageCount == 1)
{
m_settingsDockWidget->getLeftPageSelectionEdit()->setText("1");
}
else
{
m_settingsDockWidget->getLeftPageSelectionEdit()->clear();
}
updateViewDocument();
}
break;
}
case Operation::OpenRight:
{
pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true);
m_diff.stop();
std::optional<pdf::PDFDocument> document = openDocument();
if (document)
{
clear(false, true);
m_rightDocument = std::move(*document);
const size_t pageCount = m_rightDocument.getCatalog()->getPageCount();
if (pageCount > 1)
{
m_settingsDockWidget->getRightPageSelectionEdit()->setText(QString("1-%2").arg(pageCount));
}
else if (pageCount == 1)
{
m_settingsDockWidget->getRightPageSelectionEdit()->setText("1");
}
else
{
m_settingsDockWidget->getRightPageSelectionEdit()->clear();
}
updateViewDocument();
}
break;
}
case Operation::Compare:
{
pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true);
m_diff.stop();
m_diff.setOption(pdf::PDFDiff::CompareTextsAsVector, m_settingsDockWidget->isCompareTextAsVectorGraphics());
m_diff.setOption(pdf::PDFDiff::CompareWords, !m_settingsDockWidget->isCompareTextCharactersInsteadOfWords());
QString errorMessage;
pdf::PDFClosedIntervalSet rightPageIndices;
pdf::PDFClosedIntervalSet leftPageIndices = pdf::PDFClosedIntervalSet::parse(1, qMax<pdf::PDFInteger>(1, m_leftDocument.getCatalog()->getPageCount()), m_settingsDockWidget->getLeftPageSelectionEdit()->text(), &errorMessage);
if (errorMessage.isEmpty())
{
rightPageIndices = pdf::PDFClosedIntervalSet::parse(1, qMax<pdf::PDFInteger>(1, m_rightDocument.getCatalog()->getPageCount()), m_settingsDockWidget->getRightPageSelectionEdit()->text(), &errorMessage);
}
// Check if pages are succesfully parsed
if (!errorMessage.isEmpty())
{
QMessageBox::critical(this, tr("Error"), errorMessage);
break;
}
leftPageIndices.translate(-1);
rightPageIndices.translate(-1);
m_diff.setPagesForLeftDocument(std::move(leftPageIndices));
m_diff.setPagesForRightDocument(std::move(rightPageIndices));
m_diff.start();
break;
}
case Operation::Close:
{
close();
break;
}
case Operation::GetSource:
{
QDesktopServices::openUrl(QUrl("https://github.com/JakubMelka/PDF4QT"));
break;
}
case Operation::BecomeSponsor:
{
QDesktopServices::openUrl(QUrl("https://github.com/sponsors/JakubMelka"));
break;
}
case Operation::About:
{
PDFAboutDialog aboutDialog(this);
aboutDialog.exec();
break;
}
case Operation::PreviousDifference:
m_diffNavigator.goPrevious();
break;
case Operation::NextDifference:
m_diffNavigator.goNext();
break;
case Operation::FilterText:
case Operation::FilterVectorGraphics:
case Operation::FilterImages:
case Operation::FilterShading:
case Operation::FilterPageMovement:
{
updateFilteredResult();
if (ui->actionShow_Pages_with_Differences->isChecked())
{
updateCustomPageLayout();
}
break;
}
case Operation::ViewDifferences:
case Operation::ViewLeft:
case Operation::ViewRight:
case Operation::ViewOverlay:
updateViewDocument();
break;
case Operation::ShowPageswithDifferences:
updateCustomPageLayout();
break;
case Operation::DisplayDifferences:
m_settings.displayDifferences = ui->actionDisplay_Differences->isChecked();
m_pdfWidget->update();
break;
case Operation::DisplayMarkers:
m_settings.displayMarkers = ui->actionDisplay_Markers->isChecked();
m_pdfWidget->update();
break;
case Operation::SaveDifferencesToXML:
{
if (!m_filteredDiffResult.isSame())
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Select PDF document"), m_settings.directory, tr("XML file (*.xml)"));
if (!fileName.isEmpty())
{
QFile file(fileName);
if (file.open(QFile::WriteOnly | QFile::Truncate))
{
m_filteredDiffResult.saveToXML(&file);
file.close();
}
else
{
QMessageBox::critical(this, tr("Error"), tr("File '%1' cannot be opened. %2").arg(fileName, file.errorString()));
}
}
}
else
{
QMessageBox::information(this, tr("Save results to XML"), tr("Displayed results are empty. Cannot save empty results."));
}
break;
}
case Operation::CreateCompareReport:
{
if (m_filteredDiffResult.isSame())
{
break;
}
QString saveFileName = QFileDialog::getSaveFileName(this, tr("Save As"), m_settings.directory, tr("Portable Document (*.pdf);;All files (*.*)"));
if (!saveFileName.isEmpty())
{
pdf::PDFDocumentBuilder builder(m_pdfWidget->getDrawWidgetProxy()->getDocument());
m_drawInterface.drawAnnotations(m_pdfWidget->getDrawWidgetProxy()->getDocument(), &builder);
pdf::PDFDocument document = builder.build();
pdf::PDFDocumentWriter writer(m_progress);
pdf::PDFOperationResult result = writer.write(saveFileName, &document, QFile::exists(saveFileName));
if (!result)
{
QMessageBox::critical(this, tr("Error"), result.getErrorMessage());
}
}
break;
}
default:
{
Q_ASSERT(false);
break;
}
}
updateActions();
}
void MainWindow::setViewDocument(pdf::PDFDocument* document, bool updateCustomPageLayout)
{
if (document != m_pdfWidget->getDrawWidgetProxy()->getDocument())
{
m_optionalContentActivity->deleteLater();
m_optionalContentActivity = nullptr;
if (document)
{
m_optionalContentActivity = new pdf::PDFOptionalContentActivity(document, pdf::OCUsage::View, this);
}
if (document)
{
pdf::PDFModifiedDocument modifiedDocument(document, m_optionalContentActivity);
m_pdfWidget->setDocument(modifiedDocument);
}
else
{
m_pdfWidget->setDocument(pdf::PDFModifiedDocument());
}
}
if (updateCustomPageLayout)
{
this->updateCustomPageLayout();
}
}
ComparedDocumentMapper::Mode MainWindow::getDocumentViewMode() const
{
if (ui->actionView_Left->isChecked())
{
return ComparedDocumentMapper::Mode::Left;
}
if (ui->actionView_Right->isChecked())
{
return ComparedDocumentMapper::Mode::Right;
}
if (ui->actionView_Overlay->isChecked())
{
return ComparedDocumentMapper::Mode::Overlay;
}
return ComparedDocumentMapper::Mode::Combined;
}
void MainWindow::clear(bool clearLeftDocument, bool clearRightDocument)
{
setViewDocument(nullptr, true);
if (clearLeftDocument)
{
m_leftDocument = pdf::PDFDocument();
m_settingsDockWidget->getLeftPageSelectionEdit()->clear();
}
if (clearRightDocument)
{
m_rightDocument = pdf::PDFDocument();
m_settingsDockWidget->getRightPageSelectionEdit()->clear();
}
m_diffResult = pdf::PDFDiffResult();
m_filteredDiffResult = pdf::PDFDiffResult();
m_diffNavigator.update();
updateAll(false);
}
void MainWindow::updateAll(bool resetFilters)
{
if (resetFilters)
{
ui->actionFilter_Page_Movement->setChecked(m_diffResult.hasPageMoveDifferences());
ui->actionFilter_Text->setChecked(m_diffResult.hasTextDifferences());
ui->actionFilter_Vector_Graphics->setChecked(m_diffResult.hasVectorGraphicsDifferences());
ui->actionFilter_Images->setChecked(m_diffResult.hasImageDifferences());
ui->actionFilter_Shading->setChecked(m_diffResult.hasShadingDifferences());
}
updateFilteredResult();
updateViewDocument();
}
void MainWindow::updateFilteredResult()
{
m_filteredDiffResult = m_diffResult.filter(ui->actionFilter_Page_Movement->isChecked(),
ui->actionFilter_Text->isChecked(),
ui->actionFilter_Vector_Graphics->isChecked(),
ui->actionFilter_Images->isChecked(),
ui->actionFilter_Shading->isChecked());
m_diffNavigator.update();
if (m_differencesDockWidget)
{
m_differencesDockWidget->update();
}
updateActions();
}
void MainWindow::updateViewDocument()
{
pdf::PDFDocument* document = nullptr;
switch (getDocumentViewMode())
{
case ComparedDocumentMapper::Mode::Left:
document = &m_leftDocument;
break;
case ComparedDocumentMapper::Mode::Right:
document = &m_rightDocument;
break;
case ComparedDocumentMapper::Mode::Combined:
case ComparedDocumentMapper::Mode::Overlay:
document = &m_combinedDocument;
break;
}
setViewDocument(document, true);
}
void MainWindow::updateCustomPageLayout()
{
m_documentMapper.update(getDocumentViewMode(),
ui->actionShow_Pages_with_Differences->isChecked(),
m_filteredDiffResult,
&m_leftDocument,
&m_rightDocument,
m_pdfWidget->getDrawWidgetProxy()->getDocument());
m_pdfWidget->getDrawWidgetProxy()->setCustomPageLayout(m_documentMapper.getLayout());
m_pdfWidget->getDrawWidgetProxy()->setPageLayout(pdf::PageLayout::Custom);
}
void MainWindow::updateOverlayTransparency()
{
const pdf::PDFReal value = m_settingsDockWidget->getTransparencySliderValue() * 0.01;
m_pdfWidget->getDrawWidgetProxy()->setGroupTransparency(1, true, 1.0 - value);
m_pdfWidget->getDrawWidgetProxy()->setGroupTransparency(2, false, value);
m_pdfWidget->update();
}
std::optional<pdf::PDFDocument> MainWindow::openDocument()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)"));
if (fileName.isEmpty())
{
return std::nullopt;
}
auto queryPassword = [this](bool* ok)
{
*ok = false;
return QInputDialog::getText(this, tr("Encrypted document"), tr("Enter password to access document content"), QLineEdit::Password, QString(), ok);
};
// Mark current directory as this
QFileInfo fileInfo(fileName);
m_settings.directory = fileInfo.dir().absolutePath();
// Try to open a new document
pdf::PDFDocumentReader reader(nullptr, qMove(queryPassword), true, false);
pdf::PDFDocument document = reader.readFromFile(fileName);
QString errorMessage = reader.getErrorMessage();
pdf::PDFDocumentReader::Result result = reader.getReadingResult();
if (result == pdf::PDFDocumentReader::Result::OK)
{
return document;
}
else if (result == pdf::PDFDocumentReader::Result::Failed)
{
QMessageBox::critical(this, tr("Error"), errorMessage);
}
return pdf::PDFDocument();
}
void MainWindow::onProgressStarted(pdf::ProgressStartupInfo info)
{
#ifdef WIN_TASKBAR_BUTTON
m_progressTaskbarIndicator->setRange(0, 100);
m_progressTaskbarIndicator->reset();
m_progressTaskbarIndicator->show();
#else
Q_UNUSED(info);
#endif
}
void MainWindow::onProgressStep(int percentage)
{
if (m_isChangingProgressStep)
{
return;
}
pdf::PDFTemporaryValueChange guard(&m_isChangingProgressStep, true);
#ifdef WIN_TASKBAR_BUTTON
m_progressTaskbarIndicator->setValue(percentage);
#else
Q_UNUSED(percentage);
#endif
}
void MainWindow::onProgressFinished()
{
#ifdef WIN_TASKBAR_BUTTON
m_progressTaskbarIndicator->hide();
#endif
}
} // namespace pdfdiff

156
Pdf4QtDiff/mainwindow.h Normal file
View File

@ -0,0 +1,156 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDIFF_MAINWINDOW_H
#define PDFDIFF_MAINWINDOW_H
#include "utils.h"
#include "pdfdocument.h"
#include "pdfdrawwidget.h"
#include "pdfcms.h"
#include "pdfoptionalcontent.h"
#include <QMainWindow>
#include <QSignalMapper>
#ifdef WIN_TASKBAR_BUTTON
#include <QWinTaskbarButton>
#include <QWinTaskbarProgress>
#endif
namespace Ui
{
class MainWindow;
}
namespace pdfdiff
{
class SettingsDockWidget;
class DifferencesDockWidget;
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
using BaseClass = QMainWindow;
public:
explicit MainWindow(QWidget* parent);
virtual ~MainWindow() override;
enum class Operation
{
OpenLeft,
OpenRight,
Compare,
Close,
GetSource,
BecomeSponsor,
About,
PreviousDifference,
NextDifference,
CreateCompareReport,
FilterText,
FilterVectorGraphics,
FilterImages,
FilterShading,
FilterPageMovement,
ViewDifferences,
ViewLeft,
ViewRight,
ViewOverlay,
ShowPageswithDifferences,
SaveDifferencesToXML,
DisplayDifferences,
DisplayMarkers
};
virtual void showEvent(QShowEvent* event) override;
virtual void closeEvent(QCloseEvent* event) override;
private slots:
void updateActions();
void onSelectionChanged(size_t currentIndex);
private:
void onMappedActionTriggered(int actionId);
void onComparationFinished();
void onColorsChanged();
void onProgressStarted(pdf::ProgressStartupInfo info);
void onProgressStep(int percentage);
void onProgressFinished();
void loadSettings();
void saveSettings();
bool canPerformOperation(Operation operation) const;
void performOperation(Operation operation);
void setViewDocument(pdf::PDFDocument* document, bool updateCustomPageLayout);
ComparedDocumentMapper::Mode getDocumentViewMode() const;
/// Clears all data, and possibly documents also.
/// View document is set to nullptr.
/// \param clearLeftDocument Clear left document?
/// \param clearRightDocument Clear left document?
void clear(bool clearLeftDocument, bool clearRightDocument);
void updateAll(bool resetFilters);
void updateFilteredResult();
void updateViewDocument();
void updateCustomPageLayout();
void updateOverlayTransparency();
std::optional<pdf::PDFDocument> openDocument();
Ui::MainWindow* ui;
pdf::PDFProgress* m_progress;
#ifdef WIN_TASKBAR_BUTTON
QWinTaskbarButton* m_taskbarButton;
QWinTaskbarProgress* m_progressTaskbarIndicator;
#endif
pdf::PDFCMSManager* m_cmsManager;
pdf::PDFWidget* m_pdfWidget;
SettingsDockWidget* m_settingsDockWidget;
DifferencesDockWidget* m_differencesDockWidget;
pdf::PDFOptionalContentActivity* m_optionalContentActivity;
Settings m_settings;
QSignalMapper m_mapper;
pdf::PDFDiff m_diff;
bool m_isChangingProgressStep;
bool m_dontDisplayErrorMessage;
pdf::PDFDocument m_leftDocument;
pdf::PDFDocument m_rightDocument;
pdf::PDFDocument m_combinedDocument;
pdf::PDFDiffResult m_diffResult;
pdf::PDFDiffResult m_filteredDiffResult; ///< Difference result with filters applied
pdf::PDFDiffResultNavigator m_diffNavigator; ///< Difference navigator
ComparedDocumentMapper m_documentMapper;
DifferencesDrawInterface m_drawInterface;
};
} // namespace pdfdiff
#endif // PDFDIFF_MAINWINDOW_H

380
Pdf4QtDiff/mainwindow.ui Normal file
View File

@ -0,0 +1,380 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>864</width>
<height>638</height>
</rect>
</property>
<property name="windowTitle">
<string>Workspace</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout" rowstretch="0">
<item row="0" column="0" colspan="2">
<widget class="QFrame" name="documentFrame"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>864</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="actionOpen_Left"/>
<addaction name="actionOpen_Right"/>
<addaction name="actionClose"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="actionGet_Source"/>
<addaction name="actionBecomeASponsor"/>
<addaction name="actionAbout"/>
</widget>
<widget class="QMenu" name="menuToolbars">
<property name="title">
<string>&amp;Toolbars</string>
</property>
</widget>
<widget class="QMenu" name="menuCompare">
<property name="title">
<string>&amp;Compare</string>
</property>
<addaction name="actionCompare"/>
<addaction name="actionCreate_Compare_Report"/>
<addaction name="actionSave_Differences_to_XML"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>&amp;View</string>
</property>
<widget class="QMenu" name="menuView_2">
<property name="title">
<string>&amp;View</string>
</property>
<addaction name="actionView_Differences"/>
<addaction name="actionView_Left"/>
<addaction name="actionView_Right"/>
<addaction name="actionView_Overlay"/>
</widget>
<widget class="QMenu" name="menuFilter">
<property name="title">
<string>&amp;Filter</string>
</property>
<addaction name="actionFilter_Text"/>
<addaction name="actionFilter_Vector_Graphics"/>
<addaction name="actionFilter_Images"/>
<addaction name="actionFilter_Shading"/>
<addaction name="actionFilter_Page_Movement"/>
</widget>
<addaction name="actionPrevious_Difference"/>
<addaction name="actionNext_Difference"/>
<addaction name="separator"/>
<addaction name="menuView_2"/>
<addaction name="menuFilter"/>
<addaction name="actionShow_Pages_with_Differences"/>
<addaction name="actionSynchronize_View_with_Differences"/>
<addaction name="separator"/>
<addaction name="actionDisplay_Differences"/>
<addaction name="actionDisplay_Markers"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuView"/>
<addaction name="menuCompare"/>
<addaction name="menuToolbars"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionGet_Source">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/get-source.svg</normaloff>:/pdfdiff/resources/get-source.svg</iconset>
</property>
<property name="text">
<string>&amp;Get Source</string>
</property>
</action>
<action name="actionAbout">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/about.svg</normaloff>:/pdfdiff/resources/about.svg</iconset>
</property>
<property name="text">
<string>&amp;About...</string>
</property>
<property name="shortcut">
<string>F1</string>
</property>
</action>
<action name="actionOpen_Left">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/open-left.svg</normaloff>:/pdfdiff/resources/open-left.svg</iconset>
</property>
<property name="text">
<string>Open &amp;Left...</string>
</property>
</action>
<action name="actionOpen_Right">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/open-right.svg</normaloff>:/pdfdiff/resources/open-right.svg</iconset>
</property>
<property name="text">
<string>Open &amp;Right...</string>
</property>
</action>
<action name="actionCompare">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/compare.svg</normaloff>:/pdfdiff/resources/compare.svg</iconset>
</property>
<property name="text">
<string>&amp;Compare</string>
</property>
<property name="shortcut">
<string>F5</string>
</property>
</action>
<action name="actionClose">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/close.svg</normaloff>:/pdfdiff/resources/close.svg</iconset>
</property>
<property name="text">
<string>&amp;Close</string>
</property>
<property name="shortcut">
<string>Ctrl+F4</string>
</property>
</action>
<action name="actionPrevious_Difference">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/prev-diff.svg</normaloff>:/pdfdiff/resources/prev-diff.svg</iconset>
</property>
<property name="text">
<string>&amp;Previous Difference</string>
</property>
<property name="shortcut">
<string>Shift+F6</string>
</property>
</action>
<action name="actionNext_Difference">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/next-diff.svg</normaloff>:/pdfdiff/resources/next-diff.svg</iconset>
</property>
<property name="text">
<string>&amp;Next Difference</string>
</property>
<property name="shortcut">
<string>F6</string>
</property>
</action>
<action name="actionCreate_Compare_Report">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/create-compare-report.svg</normaloff>:/pdfdiff/resources/create-compare-report.svg</iconset>
</property>
<property name="text">
<string>Create Compare &amp;Report...</string>
</property>
</action>
<action name="actionFilter_Text">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/filter-text.svg</normaloff>:/pdfdiff/resources/filter-text.svg</iconset>
</property>
<property name="text">
<string>Filter &amp;Text</string>
</property>
</action>
<action name="actionFilter_Vector_Graphics">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/filter-vector-graphics.svg</normaloff>:/pdfdiff/resources/filter-vector-graphics.svg</iconset>
</property>
<property name="text">
<string>Filter &amp;Vector Graphics</string>
</property>
</action>
<action name="actionFilter_Images">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/filter-images.svg</normaloff>:/pdfdiff/resources/filter-images.svg</iconset>
</property>
<property name="text">
<string>Filter &amp;Images</string>
</property>
</action>
<action name="actionFilter_Shading">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/filter-shading.svg</normaloff>:/pdfdiff/resources/filter-shading.svg</iconset>
</property>
<property name="text">
<string>Filter &amp;Shading</string>
</property>
</action>
<action name="actionFilter_Page_Movement">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/filter-page-movement.svg</normaloff>:/pdfdiff/resources/filter-page-movement.svg</iconset>
</property>
<property name="text">
<string>Filter &amp;Page Movement</string>
</property>
</action>
<action name="actionView_Differences">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/view-differences.svg</normaloff>:/pdfdiff/resources/view-differences.svg</iconset>
</property>
<property name="text">
<string>View &amp;Differences</string>
</property>
</action>
<action name="actionView_Left">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/view-left.svg</normaloff>:/pdfdiff/resources/view-left.svg</iconset>
</property>
<property name="text">
<string>View &amp;Left</string>
</property>
</action>
<action name="actionView_Right">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/view-right.svg</normaloff>:/pdfdiff/resources/view-right.svg</iconset>
</property>
<property name="text">
<string>View &amp;Right</string>
</property>
</action>
<action name="actionView_Overlay">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/view-overlay.svg</normaloff>:/pdfdiff/resources/view-overlay.svg</iconset>
</property>
<property name="text">
<string>View &amp;Overlay</string>
</property>
</action>
<action name="actionShow_Pages_with_Differences">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/show-p-with-diff.svg</normaloff>:/pdfdiff/resources/show-p-with-diff.svg</iconset>
</property>
<property name="text">
<string>&amp;Show Pages with Differences</string>
</property>
<property name="toolTip">
<string>Show Pages with Differences</string>
</property>
</action>
<action name="actionSave_Differences_to_XML">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/save-diff-to-xml.svg</normaloff>:/pdfdiff/resources/save-diff-to-xml.svg</iconset>
</property>
<property name="text">
<string>Save Differences to &amp;XML...</string>
</property>
</action>
<action name="actionSynchronize_View_with_Differences">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/synchronize-view.svg</normaloff>:/pdfdiff/resources/synchronize-view.svg</iconset>
</property>
<property name="text">
<string>S&amp;ynchronize View with Differences</string>
</property>
</action>
<action name="actionDisplay_Differences">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/display-differences.svg</normaloff>:/pdfdiff/resources/display-differences.svg</iconset>
</property>
<property name="text">
<string>Display &amp;Differences</string>
</property>
</action>
<action name="actionDisplay_Markers">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/display-markers.svg</normaloff>:/pdfdiff/resources/display-markers.svg</iconset>
</property>
<property name="text">
<string>Display &amp;Markers</string>
</property>
</action>
<action name="actionBecomeASponsor">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdiff/resources/wallet.svg</normaloff>:/pdfdiff/resources/wallet.svg</iconset>
</property>
<property name="text">
<string>Become a &amp;Sponsor</string>
</property>
</action>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>

28
Pdf4QtDiff/resources.qrc Normal file
View File

@ -0,0 +1,28 @@
<RCC>
<qresource prefix="/pdfdiff">
<file>resources/about.svg</file>
<file>resources/close.svg</file>
<file>resources/compare.svg</file>
<file>resources/get-source.svg</file>
<file>resources/open-left.svg</file>
<file>resources/open-right.svg</file>
<file>resources/create-compare-report.svg</file>
<file>resources/filter-images.svg</file>
<file>resources/filter-page-movement.svg</file>
<file>resources/filter-shading.svg</file>
<file>resources/filter-text.svg</file>
<file>resources/filter-vector-graphics.svg</file>
<file>resources/next-diff.svg</file>
<file>resources/prev-diff.svg</file>
<file>resources/save-diff-to-xml.svg</file>
<file>resources/show-p-with-diff.svg</file>
<file>resources/synchronize-view.svg</file>
<file>resources/view-differences.svg</file>
<file>resources/view-left.svg</file>
<file>resources/view-overlay.svg</file>
<file>resources/view-right.svg</file>
<file>resources/display-differences.svg</file>
<file>resources/display-markers.svg</file>
<file>resources/wallet.svg</file>
</qresource>
</RCC>

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1022 B

After

Width:  |  Height:  |  Size: 1022 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.4 KiB

39
Pdf4QtDiff/settings.h Normal file
View File

@ -0,0 +1,39 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDIFF_SETTINGS_H
#define PDFDIFF_SETTINGS_H
#include <QColor>
namespace pdfdiff
{
struct Settings
{
QString directory;
QColor colorPageMove = QColor(35, 145, 255);
QColor colorAdded = QColor(125, 250, 0);
QColor colorRemoved = QColor(255, 50, 50);
QColor colorReplaced = QColor(255, 120, 30);
bool displayDifferences = true;
bool displayMarkers = true;
};
} // namespace pdfdiff
#endif // PDFDIFF_SETTINGS_H

View File

@ -0,0 +1,152 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "settingsdockwidget.h"
#include "ui_settingsdockwidget.h"
#include "pdfutils.h"
#include "pdfwidgetutils.h"
namespace pdfdiff
{
SettingsDockWidget::SettingsDockWidget(Settings* settings, QWidget* parent) :
QDockWidget(parent),
ui(new Ui::SettingsDockWidget),
m_settings(settings),
m_loadingColors(false)
{
ui->setupUi(this);
auto colorNames = QColor::colorNames();
for (QComboBox* comboBox : findChildren<QComboBox*>())
{
for (const QString& colorName : colorNames)
{
QColor color(colorName);
comboBox->addItem(getIconForColor(color), colorName, color);
}
connect(comboBox, &QComboBox::editTextChanged, this, &SettingsDockWidget::onEditColorChanged);
}
connect(ui->transparencySlider, &QSlider::valueChanged, this, &SettingsDockWidget::transparencySliderChanged);
toggleViewAction()->setText(tr("S&ettings"));
}
SettingsDockWidget::~SettingsDockWidget()
{
delete ui;
}
void SettingsDockWidget::setCompareTextsAsVectorGraphics(bool enabled)
{
ui->compareTextsAsVectorGraphicsCheckBox->setChecked(enabled);
}
bool SettingsDockWidget::isCompareTextAsVectorGraphics() const
{
return ui->compareTextsAsVectorGraphicsCheckBox->isChecked();
}
void SettingsDockWidget::setCompareTextCharactersInsteadOfWords(bool enabled)
{
ui->compareCharactersInsteadOfWordsCheckBox->setChecked(enabled);
}
bool SettingsDockWidget::isCompareTextCharactersInsteadOfWords() const
{
return ui->compareCharactersInsteadOfWordsCheckBox->isChecked();
}
QLineEdit* SettingsDockWidget::getLeftPageSelectionEdit() const
{
return ui->leftPageSelectionEdit;
}
QLineEdit* SettingsDockWidget::getRightPageSelectionEdit() const
{
return ui->rightPageSelectionEdit;
}
void SettingsDockWidget::loadColors()
{
pdf::PDFTemporaryValueChange guard(&m_loadingColors, true);
auto loadColor = [](QComboBox* comboBox, QColor color)
{
auto index = comboBox->findData(color);
comboBox->setCurrentIndex(index);
if (index == -1)
{
comboBox->setCurrentText(color.name());
}
};
loadColor(ui->removeColorCombo, m_settings->colorRemoved);
loadColor(ui->addColorCombo, m_settings->colorAdded);
loadColor(ui->replaceColorCombo, m_settings->colorReplaced);
loadColor(ui->moveColorCombo, m_settings->colorPageMove);
}
int SettingsDockWidget::getTransparencySliderValue() const
{
return ui->transparencySlider->value();
}
QIcon SettingsDockWidget::getIconForColor(QColor color) const
{
QIcon icon;
QSize iconSize = pdf::PDFWidgetUtils::scaleDPI(this, QSize(16, 16));
QPixmap pixmap(iconSize.width(), iconSize.height());
pixmap.fill(color);
icon.addPixmap(pixmap);
return icon;
}
void SettingsDockWidget::onEditColorChanged()
{
if (m_loadingColors)
{
return;
}
bool isChanged = false;
auto saveColor = [&isChanged](QComboBox* comboBox, QColor& color)
{
QColor oldColor = color;
color.fromString(comboBox->currentText());
isChanged = isChanged || oldColor != color;
};
saveColor(ui->removeColorCombo, m_settings->colorRemoved);
saveColor(ui->addColorCombo, m_settings->colorAdded);
saveColor(ui->replaceColorCombo, m_settings->colorReplaced);
saveColor(ui->moveColorCombo, m_settings->colorPageMove);
if (isChanged)
{
Q_EMIT colorsChanged();
}
}
} // namespace pdfdiff

View File

@ -0,0 +1,73 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDIFF_SETTINGSDOCKWIDGET_H
#define PDFDIFF_SETTINGSDOCKWIDGET_H
#include "settings.h"
#include <QDockWidget>
namespace Ui
{
class SettingsDockWidget;
}
class QLineEdit;
namespace pdfdiff
{
class SettingsDockWidget : public QDockWidget
{
Q_OBJECT
public:
explicit SettingsDockWidget(Settings* settings, QWidget* parent);
virtual ~SettingsDockWidget() override;
void setCompareTextsAsVectorGraphics(bool enabled);
bool isCompareTextAsVectorGraphics() const;
void setCompareTextCharactersInsteadOfWords(bool enabled);
bool isCompareTextCharactersInsteadOfWords() const;
QLineEdit* getLeftPageSelectionEdit() const;
QLineEdit* getRightPageSelectionEdit() const;
void loadColors();
void saveColors();
int getTransparencySliderValue() const;
signals:
void colorsChanged();
void transparencySliderChanged(int value);
private:
QIcon getIconForColor(QColor color) const;
void onEditColorChanged();
Ui::SettingsDockWidget* ui;
Settings* m_settings;
bool m_loadingColors;
};
} // namespace pdfdiff
#endif // PDFDIFF_SETTINGSDOCKWIDGET_H

563
Pdf4QtDiff/utils.cpp Normal file
View File

@ -0,0 +1,563 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "utils.h"
#include "pdfutils.h"
#include "pdfwidgetutils.h"
#include "pdfpainterutils.h"
#include "pdfdocumentbuilder.h"
#include <QPainter>
namespace pdfdiff
{
void ComparedDocumentMapper::update(ComparedDocumentMapper::Mode mode,
bool filterDifferences,
const pdf::PDFDiffResult& diff,
const pdf::PDFDocument* leftDocument,
const pdf::PDFDocument* rightDocument,
const pdf::PDFDocument* currentDocument)
{
m_layout.clear();
m_leftPageIndices.clear();
m_rightPageIndices.clear();
m_allLeft = false;
m_allRight = false;
if (!leftDocument || !rightDocument || !currentDocument)
{
return;
}
// Jakub Melka
pdf::PDFDiffResult::PageSequence pageSequence = diff.getPageSequence();
const bool isEmpty = pageSequence.empty();
if (filterDifferences)
{
pdf::PDFDiffResult::PageSequence filteredPageSequence;
std::vector<pdf::PDFInteger> leftPageIndices = diff.getChangedLeftPageIndices();
std::vector<pdf::PDFInteger> rightPageIndices = diff.getChangedRightPageIndices();
for (const pdf::PDFDiffResult::PageSequenceItem& item : pageSequence)
{
const bool isLeftModified = std::binary_search(leftPageIndices.cbegin(), leftPageIndices.cend(), item.leftPage);
const bool isRightModified = std::binary_search(rightPageIndices.cbegin(), rightPageIndices.cend(), item.rightPage);
if (isLeftModified || isRightModified)
{
filteredPageSequence.push_back(item);
}
}
pageSequence = std::move(filteredPageSequence);
}
switch (mode)
{
case ComparedDocumentMapper::Mode::Left:
{
Q_ASSERT(leftDocument == currentDocument);
m_allLeft = true;
double yPos = 0.0;
const pdf::PDFCatalog* catalog = leftDocument->getCatalog();
if (isEmpty)
{
// Just copy all pages
const size_t pageCount = catalog->getPageCount();
for (size_t i = 0; i < pageCount; ++i)
{
QSizeF pageSize = catalog->getPage(i)->getRotatedMediaBoxMM().size();
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
m_layout.emplace_back(0, i, -1, rect);
yPos += pageSize.height() + 5;
}
}
else
{
for (const pdf::PDFDiffResult::PageSequenceItem& item : pageSequence)
{
if (item.leftPage == -1)
{
continue;
}
QSizeF pageSize = catalog->getPage(item.leftPage)->getRotatedMediaBoxMM().size();
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
m_layout.emplace_back(0, item.leftPage, -1, rect);
yPos += pageSize.height() + 5;
}
}
break;
}
case ComparedDocumentMapper::Mode::Right:
{
Q_ASSERT(rightDocument == currentDocument);
m_allRight = true;
double yPos = 0.0;
const pdf::PDFCatalog* catalog = rightDocument->getCatalog();
if (isEmpty)
{
// Just copy all pages
const size_t pageCount = catalog->getPageCount();
for (size_t i = 0; i < pageCount; ++i)
{
QSizeF pageSize = catalog->getPage(i)->getRotatedMediaBoxMM().size();
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
m_layout.emplace_back(0, i, -1, rect);
yPos += pageSize.height() + 5;
}
}
else
{
for (const pdf::PDFDiffResult::PageSequenceItem& item : pageSequence)
{
if (item.rightPage == -1)
{
continue;
}
QSizeF pageSize = catalog->getPage(item.rightPage)->getRotatedMediaBoxMM().size();
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
m_layout.emplace_back(0, item.rightPage, -1, rect);
yPos += pageSize.height() + 5;
}
}
break;
}
case ComparedDocumentMapper::Mode::Combined:
case ComparedDocumentMapper::Mode::Overlay:
{
double yPos = 0.0;
const pdf::PDFCatalog* catalog = currentDocument->getCatalog();
pdf::PDFInteger offset = leftDocument->getCatalog()->getPageCount();
for (const pdf::PDFDiffResult::PageSequenceItem& item : pageSequence)
{
double yAdvance = 0.0;
if (item.leftPage != -1)
{
QSizeF pageSize = catalog->getPage(item.leftPage)->getRotatedMediaBoxMM().size();
QRectF rect;
pdf::PDFInteger groupIndex = -1;
if (mode == ComparedDocumentMapper::Mode::Combined)
{
rect = QRectF(-pageSize.width() - 5, yPos, pageSize.width(), pageSize.height());
}
else
{
if (item.rightPage != -1)
{
groupIndex = 1;
}
rect = QRectF(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
}
m_layout.emplace_back(0, item.leftPage, groupIndex, rect);
yAdvance = pageSize.height() + 5;
m_leftPageIndices[item.leftPage] = item.leftPage;
}
if (item.rightPage != -1)
{
pdf::PDFInteger rightPageIndex = item.rightPage + offset;
QSizeF pageSize = catalog->getPage(rightPageIndex)->getRotatedMediaBoxMM().size();
QRectF rect;
pdf::PDFInteger groupIndex = -1;
if (mode == ComparedDocumentMapper::Mode::Combined)
{
rect = QRectF(5, yPos, pageSize.width(), pageSize.height());
}
else
{
if (item.leftPage != -1)
{
groupIndex = 2;
}
rect = QRectF(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
}
m_layout.emplace_back(0, rightPageIndex, groupIndex, rect);
yAdvance = qMax(yAdvance, pageSize.height() + 5);
m_rightPageIndices[rightPageIndex] = item.rightPage;
}
yPos += yAdvance;
}
break;
}
default:
Q_ASSERT(false);
break;
}
}
pdf::PDFInteger ComparedDocumentMapper::getLeftPageIndex(pdf::PDFInteger pageIndex) const
{
if (m_allLeft)
{
return pageIndex;
}
auto it = m_leftPageIndices.find(pageIndex);
if (it != m_leftPageIndices.cend())
{
return it->second;
}
return -1;
}
pdf::PDFInteger ComparedDocumentMapper::getRightPageIndex(pdf::PDFInteger pageIndex) const
{
if (m_allRight)
{
return pageIndex;
}
auto it = m_rightPageIndices.find(pageIndex);
if (it != m_rightPageIndices.cend())
{
return it->second;
}
return -1;
}
pdf::PDFInteger ComparedDocumentMapper::getPageIndexFromLeftPageIndex(pdf::PDFInteger leftPageIndex) const
{
if (m_allLeft)
{
return leftPageIndex;
}
for (const auto& indexItem : m_leftPageIndices)
{
if (indexItem.second == leftPageIndex)
{
return indexItem.first;
}
}
return -1;
}
pdf::PDFInteger ComparedDocumentMapper::getPageIndexFromRightPageIndex(pdf::PDFInteger rightPageIndex) const
{
if (m_allRight)
{
return rightPageIndex;
}
for (const auto& indexItem : m_rightPageIndices)
{
if (indexItem.second == rightPageIndex)
{
return indexItem.first;
}
}
return -1;
}
DifferencesDrawInterface::DifferencesDrawInterface(const Settings* settings,
const ComparedDocumentMapper* mapper,
const pdf::PDFDiffResult* diffResult) :
m_settings(settings),
m_mapper(mapper),
m_diffResult(diffResult)
{
}
void DifferencesDrawInterface::drawPage(QPainter* painter,
pdf::PDFInteger pageIndex,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
QList<pdf::PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
if (!m_settings->displayDifferences)
{
return;
}
const size_t differencesCount = m_diffResult->getDifferencesCount();
const pdf::PDFInteger leftPageIndex = m_mapper->getLeftPageIndex(pageIndex);
const pdf::PDFInteger rightPageIndex = m_mapper->getRightPageIndex(pageIndex);
std::optional<size_t> pageMoveIndex;
if (leftPageIndex != -1)
{
for (size_t i = 0; i < differencesCount; ++i)
{
auto leftRectangles = m_diffResult->getLeftRectangles(i);
for (auto it = leftRectangles.first; it != leftRectangles.second; ++it)
{
const auto& item = *it;
if (item.first == leftPageIndex)
{
QColor color = getColorForIndex(i);
drawRectangle(painter, pagePointToDevicePointMatrix, item.second, color);
drawMarker(painter, pagePointToDevicePointMatrix, item.second, color, true);
}
}
if (m_diffResult->isPageMoveAddRemoveDifference(i) && m_diffResult->getLeftPage(i) == leftPageIndex)
{
pageMoveIndex = i;
}
}
}
if (rightPageIndex != -1)
{
for (size_t i = 0; i < differencesCount; ++i)
{
auto rightRectangles = m_diffResult->getRightRectangles(i);
for (auto it = rightRectangles.first; it != rightRectangles.second; ++it)
{
const auto& item = *it;
if (item.first == rightPageIndex)
{
QColor color = getColorForIndex(i);
drawRectangle(painter, pagePointToDevicePointMatrix, item.second, color);
drawMarker(painter, pagePointToDevicePointMatrix, item.second, color, false);
}
}
if (m_diffResult->isPageMoveAddRemoveDifference(i) && m_diffResult->getRightPage(i) == rightPageIndex)
{
pageMoveIndex = i;
}
}
}
if (pageMoveIndex)
{
QString text;
switch (m_diffResult->getType(*pageMoveIndex))
{
case pdf::PDFDiffResult::Type::PageAdded:
text = " + ";
break;
case pdf::PDFDiffResult::Type::PageRemoved:
text = " - ";
break;
case pdf::PDFDiffResult::Type::PageMoved:
text = QString("%1🠖%2").arg(m_diffResult->getLeftPage(*pageMoveIndex) + 1).arg(m_diffResult->getRightPage(*pageMoveIndex) + 1);
break;
default:
Q_ASSERT(false);
break;
}
QColor color = getColorForIndex(*pageMoveIndex);
QPointF targetPoint = pagePointToDevicePointMatrix.map(QPointF(5, 5));
pdf::PDFPainterHelper::drawBubble(painter, targetPoint.toPoint(), color, text, Qt::AlignRight | Qt::AlignTop);
}
}
QColor DifferencesDrawInterface::getColorForIndex(size_t index) const
{
QColor color;
const size_t resultIndex = index;
if (m_diffResult->isReplaceDifference(resultIndex))
{
color = m_settings->colorReplaced;
}
else if (m_diffResult->isRemoveDifference(resultIndex))
{
color = m_settings->colorRemoved;
}
else if (m_diffResult->isAddDifference(resultIndex))
{
color = m_settings->colorAdded;
}
else if (m_diffResult->isPageMoveDifference(resultIndex))
{
color = m_settings->colorPageMove;
}
return color;
}
void DifferencesDrawInterface::drawPostRendering(QPainter* painter, QRect rect) const
{
Q_UNUSED(painter);
Q_UNUSED(rect);
}
void DifferencesDrawInterface::drawAnnotations(const pdf::PDFDocument* document,
pdf::PDFDocumentBuilder* builder)
{
pdf::PDFInteger pageCount = document->getCatalog()->getPageCount();
QString title = pdf::PDFSysUtils::getUserName();
QString subject = tr("Difference");
for (pdf::PDFInteger pageIndex = 0; pageIndex < pageCount; ++pageIndex)
{
const size_t differencesCount = m_diffResult->getDifferencesCount();
const pdf::PDFInteger leftPageIndex = m_mapper->getLeftPageIndex(pageIndex);
const pdf::PDFInteger rightPageIndex = m_mapper->getRightPageIndex(pageIndex);
const pdf::PDFPage* page = document->getCatalog()->getPage(pageIndex);
pdf::PDFObjectReference reference = page->getPageReference();
if (leftPageIndex != -1)
{
for (size_t i = 0; i < differencesCount; ++i)
{
auto leftRectangles = m_diffResult->getLeftRectangles(i);
for (auto it = leftRectangles.first; it != leftRectangles.second; ++it)
{
const auto& item = *it;
if (item.first == leftPageIndex)
{
QColor color = getColorForIndex(i);
const QRectF& rect = item.second;
QPolygonF polygon;
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft();
pdf::PDFObjectReference annotation = builder->createAnnotationPolygon(reference, polygon, 1.0, color, color, title, subject, m_diffResult->getMessage(i));
builder->setAnnotationOpacity(annotation, 0.3);
builder->updateAnnotationAppearanceStreams(annotation);
}
}
}
}
if (rightPageIndex != -1)
{
for (size_t i = 0; i < differencesCount; ++i)
{
auto rightRectangles = m_diffResult->getRightRectangles(i);
for (auto it = rightRectangles.first; it != rightRectangles.second; ++it)
{
const auto& item = *it;
if (item.first == rightPageIndex)
{
QColor color = getColorForIndex(i);
const QRectF& rect = item.second;
QPolygonF polygon;
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft();
pdf::PDFObjectReference annotation = builder->createAnnotationPolygon(reference, polygon, 1.0, color, color, title, subject, m_diffResult->getMessage(i));
builder->setAnnotationOpacity(annotation, 0.3);
builder->updateAnnotationAppearanceStreams(annotation);
}
}
}
}
}
}
void DifferencesDrawInterface::drawRectangle(QPainter* painter,
const QTransform& pagePointToDevicePointMatrix,
const QRectF& rect,
QColor color) const
{
color.setAlphaF(0.5);
QRectF resultRect = pagePointToDevicePointMatrix.mapRect(rect);
painter->fillRect(resultRect, color);
}
void DifferencesDrawInterface::drawMarker(QPainter* painter,
const QTransform& pagePointToDevicePointMatrix,
const QRectF& rect,
QColor color,
bool isLeft) const
{
if (!m_settings->displayMarkers)
{
return;
}
pdf::PDFPainterStateGuard guard(painter);
QRectF deviceRect = pagePointToDevicePointMatrix.mapRect(rect);
QPointF snapPoint;
QPointF markPoint;
if (isLeft)
{
snapPoint.ry() = deviceRect.center().y();
snapPoint.rx() = deviceRect.left();
markPoint = snapPoint;
markPoint.rx() = 0;
}
else
{
snapPoint.ry() = deviceRect.center().y();
snapPoint.rx() = deviceRect.right();
markPoint = snapPoint;
markPoint.rx() = painter->device()->width();
}
const qreal lineWidthF = pdf::PDFWidgetUtils::scaleDPI_y(painter->device(), 2);
QPen pen(Qt::DotLine);
pen.setColor(color);
pen.setWidthF(lineWidthF);
painter->setBrush(Qt::NoBrush);
painter->setPen(pen);
painter->drawLine(snapPoint, markPoint);
const qreal markSizeX = pdf::PDFWidgetUtils::scaleDPI_x(painter->device(), 10);
const qreal markSizeY = pdf::PDFWidgetUtils::scaleDPI_y(painter->device(), 10);
QPointF ptc = markPoint;
QPointF ptTop = ptc;
QPointF ptBottom = ptc;
ptTop.ry() -= markSizeY;
ptBottom.ry() += markSizeY;
ptc.rx() += isLeft ? markSizeX : -markSizeX;
std::array points = { ptTop, ptc, ptBottom };
painter->setPen(Qt::NoPen);
painter->setBrush(QBrush(color));
painter->drawConvexPolygon(points.data(), int(points.size()));
}
} // namespace pdfdiff

126
Pdf4QtDiff/utils.h Normal file
View File

@ -0,0 +1,126 @@
// Copyright (C) 2021-2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDIFF_UTILS_H
#define PDFDIFF_UTILS_H
#include "settings.h"
#include "pdfdiff.h"
#include "pdfdrawspacecontroller.h"
#include "pdfdocumentdrawinterface.h"
namespace pdf
{
class PDFDocumentBuilder;
} // namespace pdf
namespace pdfdiff
{
class ComparedDocumentMapper
{
public:
enum class Mode
{
Left,
Right,
Combined,
Overlay
};
void update(Mode mode,
bool filterDifferences,
const pdf::PDFDiffResult& diff,
const pdf::PDFDocument* leftDocument,
const pdf::PDFDocument* rightDocument,
const pdf::PDFDocument* currentDocument);
const pdf::PDFDrawSpaceController::LayoutItems& getLayout() const { return m_layout; }
void setPageSequence(const pdf::PDFDiffResult::PageSequence& sequence) { m_pageSequence = sequence; }
/// Returns left page index (that means page index in left document),
/// if it doesn't exist, -1 is returned.
/// \param pageIndex Actual page index
pdf::PDFInteger getLeftPageIndex(pdf::PDFInteger pageIndex) const;
/// Returns right page index (that means page index in right document),
/// if it doesn't exist, -1 is returned.
/// \param pageIndex Actual page index
pdf::PDFInteger getRightPageIndex(pdf::PDFInteger pageIndex) const;
/// Returns actual page index from left page index, or -1.
/// \param leftPageIndex Left page index
pdf::PDFInteger getPageIndexFromLeftPageIndex(pdf::PDFInteger leftPageIndex) const;
/// Returns actual page index from right page index, or -1.
/// \param rightPageIndex Right page index
pdf::PDFInteger getPageIndexFromRightPageIndex(pdf::PDFInteger rightPageIndex) const;
private:
pdf::PDFDrawSpaceController::LayoutItems m_layout;
bool m_allLeft = false;
bool m_allRight = false;
std::map<pdf::PDFInteger, pdf::PDFInteger> m_leftPageIndices;
std::map<pdf::PDFInteger, pdf::PDFInteger> m_rightPageIndices;
pdf::PDFDiffResult::PageSequence m_pageSequence;
};
class DifferencesDrawInterface : public pdf::IDocumentDrawInterface
{
Q_DECLARE_TR_FUNCTIONS(pdfdiff::DifferencesDrawInterface)
public:
explicit DifferencesDrawInterface(const Settings* settings,
const ComparedDocumentMapper* mapper,
const pdf::PDFDiffResult* diffResult);
virtual void drawPage(QPainter* painter, pdf::PDFInteger pageIndex,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
QList<pdf::PDFRenderError>& errors) const override;
virtual void drawPostRendering(QPainter* painter, QRect rect) const override;
/// Draw annotations for differences
/// \param document Document
/// \param builder Builder
void drawAnnotations(const pdf::PDFDocument* document, pdf::PDFDocumentBuilder* builder);
private:
void drawRectangle(QPainter* painter,
const QTransform& pagePointToDevicePointMatrix,
const QRectF& rect,
QColor color) const;
void drawMarker(QPainter* painter,
const QTransform& pagePointToDevicePointMatrix,
const QRectF& rect,
QColor color,
bool isLeft) const;
QColor getColorForIndex(size_t index) const;
const Settings* m_settings;
const ComparedDocumentMapper* m_mapper;
const pdf::PDFDiffResult* m_diffResult;
};
} // namespace pdfdiff
#endif // PDFDIFF_UTILS_H

View File

@ -1,40 +0,0 @@
# Copyright (C) 2022 Jakub Melka
#
# This file is part of PDF4QT.
#
# PDF4QT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# with the written consent of the copyright owner, any later version.
#
# PDF4QT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
add_executable(Pdf4QtDocDiff
aboutdialog.cpp
differencesdockwidget.cpp
main.cpp
mainwindow.cpp
settingsdockwidget.cpp
utils.cpp
aboutdialog.ui
differencesdockwidget.ui
mainwindow.ui
settingsdockwidget.ui
resources.qrc
icon.rc
)
target_link_libraries(Pdf4QtDocDiff PRIVATE Pdf4QtLib Qt6::Core Qt6::Gui Qt6::Widgets Qt6::OpenGLWidgets)
set_target_properties(Pdf4QtDocDiff PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
install(TARGETS Pdf4QtDocDiff)

View File

@ -1,64 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include "pdfutils.h"
#include "pdfwidgetutils.h"
namespace pdfdocdiff
{
PDFAboutDialog::PDFAboutDialog(QWidget* parent) :
QDialog(parent),
ui(new Ui::PDFAboutDialog)
{
ui->setupUi(this);
QString html = ui->copyrightLabel->text();
html.replace("PdfForQtViewer", QString("%1 %2").arg(QApplication::applicationDisplayName(), QApplication::applicationVersion()));
ui->copyrightLabel->setText(html);
std::vector<pdf::PDFDependentLibraryInfo> infos = pdf::PDFDependentLibraryInfo::getLibraryInfo();
ui->tableWidget->setColumnCount(4);
ui->tableWidget->setRowCount(static_cast<int>(infos.size()));
ui->tableWidget->setHorizontalHeaderLabels(QStringList() << tr("Library") << tr("Version") << tr("License") << tr("URL"));
ui->tableWidget->setEditTriggers(QTableWidget::NoEditTriggers);
ui->tableWidget->setSelectionMode(QTableView::SingleSelection);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
for (int i = 0; i < infos.size(); ++i)
{
const pdf::PDFDependentLibraryInfo& info = infos[i];
ui->tableWidget->setItem(i, 0, new QTableWidgetItem(info.library));
ui->tableWidget->setItem(i, 1, new QTableWidgetItem(info.version));
ui->tableWidget->setItem(i, 2, new QTableWidgetItem(info.license));
ui->tableWidget->setItem(i, 3, new QTableWidgetItem(info.url));
}
pdf::PDFWidgetUtils::scaleWidget(this, QSize(750, 600));
pdf::PDFWidgetUtils::style(this);
}
PDFAboutDialog::~PDFAboutDialog()
{
delete ui;
}
} // namespace pdfdocdiff

View File

@ -1,45 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDOCDIFF_PDFABOUTDIALOG_H
#define PDFDOCDIFF_PDFABOUTDIALOG_H
#include <QDialog>
namespace Ui
{
class PDFAboutDialog;
}
namespace pdfdocdiff
{
class PDFAboutDialog : public QDialog
{
Q_OBJECT
public:
explicit PDFAboutDialog(QWidget* parent);
virtual ~PDFAboutDialog() override;
private:
Ui::PDFAboutDialog* ui;
};
} // namespace pdfdocdiff
#endif // PDFDOCDIFF_PDFABOUTDIALOG_H

View File

@ -1,269 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PDFAboutDialog</class>
<widget class="QDialog" name="PDFAboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>600</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>900</width>
<height>600</height>
</size>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="copyrightLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;PdfForQtViewer&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Copyright 2018-2023 Jakub Melka. All rights reserved.&lt;/p&gt;&lt;p&gt;THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEdit">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; GNU LESSER GENERAL PUBLIC LICENSE&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Version 3, 29 June 2007&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Copyright (C) 2007 Free Software Foundation, Inc. &amp;lt;https://fsf.org/&amp;gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Everyone is permitted to copy and distribute verbatim copies&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; of this license document, but changing it is not allowed.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; This version of the GNU Lesser General Public License incorporates&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;the terms and conditions of version 3 of the GNU General Public&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;License, supplemented by the additional permissions listed below.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 0. Additional Definitions.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; As used herein, &amp;quot;this License&amp;quot; refers to version 3 of the GNU Lesser&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;General Public License, and the &amp;quot;GNU GPL&amp;quot; refers to version 3 of the GNU&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;General Public License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; &amp;quot;The Library&amp;quot; refers to a covered work governed by this License,&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;other than an Application or a Combined Work as defined below.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; An &amp;quot;Application&amp;quot; is any work that makes use of an interface provided&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;by the Library, but which is not otherwise based on the Library.&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Defining a subclass of a class defined by the Library is deemed a mode&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;of using an interface provided by the Library.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; A &amp;quot;Combined Work&amp;quot; is a work produced by combining or linking an&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Application with the Library. The particular version of the Library&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;with which the Combined Work was made is also called the &amp;quot;Linked&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Version&amp;quot;.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; The &amp;quot;Minimal Corresponding Source&amp;quot; for a Combined Work means the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Corresponding Source for the Combined Work, excluding any source code&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;for portions of the Combined Work that, considered in isolation, are&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;based on the Application, and not on the Linked Version.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; The &amp;quot;Corresponding Application Code&amp;quot; for a Combined Work means the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;object code and/or source code for the Application, including any data&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;and utility programs needed for reproducing the Combined Work from the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Application, but excluding the System Libraries of the Combined Work.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 1. Exception to Section 3 of the GNU GPL.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; You may convey a covered work under sections 3 and 4 of this License&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;without being bound by section 3 of the GNU GPL.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 2. Conveying Modified Versions.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; If you modify a copy of the Library, and, in your modifications, a&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;facility refers to a function or data to be supplied by an Application&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;that uses the facility (other than as an argument passed when the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;facility is invoked), then you may convey a copy of the modified&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;version:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a) under this License, provided that you make a good faith effort to&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; ensure that, in the event an Application does not supply the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; function or data, the facility still operates, and performs&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; whatever part of its purpose remains meaningful, or&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; b) under the GNU GPL, with none of the additional permissions of&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; this License applicable to that copy.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 3. Object Code Incorporating Material from Library Header Files.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; The object code form of an Application may incorporate material from&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;a header file that is part of the Library. You may convey such object&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;code under terms of your choice, provided that, if the incorporated&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;material is not limited to numerical parameters, data structure&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;layouts and accessors, or small macros, inline functions and templates&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;(ten or fewer lines in length), you do both of the following:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a) Give prominent notice with each copy of the object code that the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Library is used in it and that the Library and its use are&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; covered by this License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; b) Accompany the object code with a copy of the GNU GPL and this license&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; document.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 4. Combined Works.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; You may convey a Combined Work under terms of your choice that,&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;taken together, effectively do not restrict modification of the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;portions of the Library contained in the Combined Work and reverse&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;engineering for debugging such modifications, if you also do each of&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;the following:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a) Give prominent notice with each copy of the Combined Work that&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; the Library is used in it and that the Library and its use are&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; covered by this License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; b) Accompany the Combined Work with a copy of the GNU GPL and this license&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; document.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; c) For a Combined Work that displays copyright notices during&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; execution, include the copyright notice for the Library among&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; these notices, as well as a reference directing the user to the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; copies of the GNU GPL and this license document.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; d) Do one of the following:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 0) Convey the Minimal Corresponding Source under the terms of this&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; License, and the Corresponding Application Code in a form&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; suitable for, and under terms that permit, the user to&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; recombine or relink the Application with a modified version of&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; the Linked Version to produce a modified Combined Work, in the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; manner specified by section 6 of the GNU GPL for conveying&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Corresponding Source.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 1) Use a suitable shared library mechanism for linking with the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Library. A suitable mechanism is one that (a) uses at run time&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a copy of the Library already present on the user's computer&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; system, and (b) will operate properly with a modified version&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; of the Library that is interface-compatible with the Linked&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Version.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; e) Provide Installation Information, but only if you would otherwise&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; be required to provide such information under section 6 of the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; GNU GPL, and only to the extent that such information is&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; necessary to install and execute a modified version of the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Combined Work produced by recombining or relinking the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Application with a modified version of the Linked Version. (If&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; you use option 4d0, the Installation Information must accompany&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; the Minimal Corresponding Source and Corresponding Application&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Code. If you use option 4d1, you must provide the Installation&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Information in the manner specified by section 6 of the GNU GPL&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; for conveying Corresponding Source.)&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 5. Combined Libraries.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; You may place library facilities that are a work based on the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Library side by side in a single library together with other library&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;facilities that are not Applications and are not covered by this&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;License, and convey such a combined library under terms of your&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;choice, if you do both of the following:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a) Accompany the combined library with a copy of the same work based&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; on the Library, uncombined with any other library facilities,&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; conveyed under the terms of this License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; b) Give prominent notice with the combined library that part of it&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; is a work based on the Library, and explaining where to find the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; accompanying uncombined form of the same work.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 6. Revised Versions of the GNU Lesser General Public License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; The Free Software Foundation may publish revised and/or new versions&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;of the GNU Lesser General Public License from time to time. Such new&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;versions will be similar in spirit to the present version, but may&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;differ in detail to address new problems or concerns.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Each version is given a distinguishing version number. If the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Library as you received it specifies that a certain numbered version&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;of the GNU Lesser General Public License &amp;quot;or any later version&amp;quot;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;applies to it, you have the option of following the terms and&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;conditions either of that published version or of any later version&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;published by the Free Software Foundation. If the Library as you&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;received it does not specify a version number of the GNU Lesser&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;General Public License, you may choose any version of the GNU Lesser&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;General Public License ever published by the Free Software Foundation.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; If the Library as you received it specifies that a proxy can decide&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;whether future versions of the GNU Lesser General Public License shall&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;apply, that proxy's public statement of acceptance of any version is&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;permanent authorization for you to choose that version for the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Library.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="usedLibrariesLabel">
<property name="text">
<string>Used libraries</string>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="tableWidget"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PDFAboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PDFAboutDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,305 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "differencesdockwidget.h"
#include "ui_differencesdockwidget.h"
#include "pdfdiff.h"
#include "pdfwidgetutils.h"
#include <QPixmap>
#include <QPainter>
#include <QTreeWidgetItem>
namespace pdfdocdiff
{
DifferenceItemDelegate::DifferenceItemDelegate(QObject* parent) :
BaseClass(parent)
{
}
void DifferenceItemDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
BaseClass::paint(painter, option, index);
}
QSize DifferenceItemDelegate::sizeHint(const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
QStyleOptionViewItem adjustedOption = option;
if (!option.rect.isValid())
{
// Jakub Melka: Why this? We need to use text wrapping. Unfortunately,
// standard delegate needs correct text rectangle (at least rectangle width),
// for word wrap calculation. So we must manually calculate rectangle width.
// Of course, we cant use visualRect of the tree widget, because of cyclical
// dependence.
const QTreeWidget* treeWidget = qobject_cast<const QTreeWidget*>(option.widget);
int xOffset = treeWidget->columnViewportPosition(index.column());
int height = option.fontMetrics.lineSpacing();
int yOffset = 0;
int width = treeWidget->columnWidth(index.column());
int level = treeWidget->rootIsDecorated() ? 1 : 0;
QModelIndex currentIndex = index.parent();
while (currentIndex.isValid())
{
++level;
currentIndex = currentIndex.parent();
}
xOffset += level * treeWidget->indentation();
adjustedOption.rect = QRect(xOffset, yOffset, width - xOffset, height);
}
return BaseClass::sizeHint(adjustedOption, index);
}
DifferencesDockWidget::DifferencesDockWidget(QWidget* parent,
pdf::PDFDiffResult* unfilteredDiffResult,
pdf::PDFDiffResult* diffResult,
pdf::PDFDiffResultNavigator* diffNavigator,
Settings* settings) :
QDockWidget(parent),
ui(new Ui::DifferencesDockWidget),
m_unfilteredDiffResult(unfilteredDiffResult),
m_diffResult(diffResult),
m_diffNavigator(diffNavigator),
m_settings(settings),
m_disableChangeSelectedResultIndex(false)
{
ui->setupUi(this);
ui->differencesTreeWidget->setItemDelegate(new DifferenceItemDelegate(this));
ui->differencesTreeWidget->setIconSize(pdf::PDFWidgetUtils::scaleDPI(ui->differencesTreeWidget, QSize(16, 16)));
connect(diffNavigator, &pdf::PDFDiffResultNavigator::selectionChanged, this, &DifferencesDockWidget::onSelectionChanged);
connect(ui->differencesTreeWidget, &QTreeWidget::currentItemChanged, this, &DifferencesDockWidget::onCurrentItemChanged);
setMinimumWidth(pdf::PDFWidgetUtils::scaleDPI_x(this, 120));
}
DifferencesDockWidget::~DifferencesDockWidget()
{
delete ui;
}
QColor DifferencesDockWidget::getColorForIndex(size_t index) const
{
QColor color;
const size_t resultIndex = index;
if (m_diffResult->isReplaceDifference(resultIndex))
{
color = m_settings->colorReplaced;
}
else if (m_diffResult->isRemoveDifference(resultIndex))
{
color = m_settings->colorRemoved;
}
else if (m_diffResult->isAddDifference(resultIndex))
{
color = m_settings->colorAdded;
}
else if (m_diffResult->isPageMoveDifference(resultIndex))
{
color = m_settings->colorPageMove;
}
return color;
}
QModelIndex DifferencesDockWidget::findResultIndex(size_t index) const
{
QAbstractItemModel* model = ui->differencesTreeWidget->model();
const int count = ui->differencesTreeWidget->topLevelItemCount();
for (int i = 0; i < count; ++i)
{
QModelIndex parentIndex = model->index(i, 0);
if (parentIndex.isValid())
{
const int childCount = model->rowCount(parentIndex);
for (int j = 0; j < childCount; ++j)
{
QModelIndex childIndex = model->index(j, 0, parentIndex);
QVariant childUserData = childIndex.data(Qt::UserRole);
if (childUserData.isValid())
{
if (childUserData.toULongLong() == index)
{
return childIndex;
}
}
}
}
}
return QModelIndex();
}
void DifferencesDockWidget::update()
{
ui->differencesTreeWidget->clear();
QList<QTreeWidgetItem*> topItems;
QLocale locale;
if (m_diffResult && !m_diffResult->isSame())
{
std::map<QRgb, QIcon> icons;
auto getIcon = [this, &icons](QColor color)
{
auto it = icons.find(color.rgb());
if (it == icons.end())
{
QPixmap pixmap(ui->differencesTreeWidget->iconSize());
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setPen(Qt::NoPen);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(QBrush(color));
painter.drawEllipse(0, 0, pixmap.width(), pixmap.height());
painter.end();
QIcon icon(pixmap);
it = icons.insert(std::make_pair(color.rgb(), std::move(icon))).first;
}
return it->second;
};
const size_t differenceCount = m_diffResult->getDifferencesCount();
const size_t unfilteredDifferenceCount = m_unfilteredDiffResult->getDifferencesCount();
const size_t hiddenDifferences = unfilteredDifferenceCount - differenceCount;
if (hiddenDifferences > 0)
{
ui->infoTextLabel->setText(tr("%1 Differences (+%2 hidden)").arg(differenceCount).arg(hiddenDifferences));
}
else
{
ui->infoTextLabel->setText(tr("%1 Differences").arg(differenceCount));
}
pdf::PDFInteger lastLeftPageIndex = -1;
pdf::PDFInteger lastRightPageIndex = -1;
for (size_t i = 0; i < differenceCount; ++i)
{
pdf::PDFInteger pageIndexLeft = m_diffResult->getLeftPage(i);
pdf::PDFInteger pageIndexRight = m_diffResult->getRightPage(i);
if (lastLeftPageIndex != pageIndexLeft ||
lastRightPageIndex != pageIndexRight ||
topItems.empty())
{
// Create new top level item
QStringList captionParts;
captionParts << QString("#%1:").arg(topItems.size() + 1);
if (pageIndexLeft == pageIndexRight)
{
captionParts << tr("Page %1").arg(locale.toString(pageIndexLeft + 1));
}
else
{
if (pageIndexLeft != -1)
{
captionParts << tr("Left %1").arg(locale.toString(pageIndexLeft + 1));
}
if (pageIndexRight != -1)
{
captionParts << tr("Right %1").arg(locale.toString(pageIndexRight + 1));
}
}
QTreeWidgetItem* item = new QTreeWidgetItem(QStringList() << captionParts.join(" "));
topItems << item;
lastLeftPageIndex = pageIndexLeft;
lastRightPageIndex = pageIndexRight;
}
Q_ASSERT(!topItems.isEmpty());
QTreeWidgetItem* parent = topItems.back();
QTreeWidgetItem* item = new QTreeWidgetItem(parent, QStringList() << m_diffResult->getMessage(i));
item->setData(0, Qt::UserRole, QVariant(static_cast<qint64>(i)));
QColor color = getColorForIndex(i);
if (color.isValid())
{
item->setData(0, Qt::DecorationRole, getIcon(color));
}
}
}
else
{
ui->infoTextLabel->setText(tr("No Differences Found!"));
}
ui->differencesTreeWidget->addTopLevelItems(topItems);
ui->differencesTreeWidget->expandAll();
}
void DifferencesDockWidget::onSelectionChanged(size_t currentIndex)
{
if (m_disableChangeSelectedResultIndex)
{
return;
}
pdf::PDFTemporaryValueChange guard(&m_disableChangeSelectedResultIndex, true);
QModelIndex index = findResultIndex(currentIndex);
if (index.isValid())
{
ui->differencesTreeWidget->scrollTo(index);
ui->differencesTreeWidget->setCurrentIndex(index);
}
}
void DifferencesDockWidget::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
{
Q_UNUSED(previous);
if (m_disableChangeSelectedResultIndex || !current)
{
return;
}
pdf::PDFTemporaryValueChange guard(&m_disableChangeSelectedResultIndex, true);
QVariant childUserData = current->data(0, Qt::UserRole);
if (childUserData.isValid())
{
m_diffNavigator->select(childUserData.toULongLong());
}
}
} // namespace pdfdocdiff

View File

@ -1,89 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef DIFFERENCESDOCKWIDGET_H
#define DIFFERENCESDOCKWIDGET_H
#include "settings.h"
#include <QDockWidget>
#include <QItemDelegate>
namespace Ui
{
class DifferencesDockWidget;
}
class QTreeWidgetItem;
namespace pdf
{
class PDFDiffResult;
class PDFDiffResultNavigator;
}
namespace pdfdocdiff
{
class DifferenceItemDelegate : public QItemDelegate
{
Q_OBJECT
private:
using BaseClass = QItemDelegate;
public:
DifferenceItemDelegate(QObject* parent);
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
};
class DifferencesDockWidget : public QDockWidget
{
Q_OBJECT
public:
explicit DifferencesDockWidget(QWidget* parent,
pdf::PDFDiffResult* unfilteredDiffResult,
pdf::PDFDiffResult* diffResult,
pdf::PDFDiffResultNavigator* diffNavigator,
Settings* settings);
virtual ~DifferencesDockWidget() override;
void update();
private slots:
void onSelectionChanged(size_t currentIndex);
void onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
private:
Ui::DifferencesDockWidget* ui;
QColor getColorForIndex(size_t index) const;
QModelIndex findResultIndex(size_t index) const;
pdf::PDFDiffResult* m_unfilteredDiffResult;
pdf::PDFDiffResult* m_diffResult;
pdf::PDFDiffResultNavigator* m_diffNavigator;
Settings* m_settings;
bool m_disableChangeSelectedResultIndex;
};
} // namespace pdfdocdiff
#endif // DIFFERENCESDOCKWIDGET_H

View File

@ -1,51 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdfconstants.h"
#include "mainwindow.h"
#include <QApplication>
#include <QCommandLineParser>
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
#if !defined(Q_OS_WIN)
QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, true);
#endif
QApplication application(argc, argv);
QCoreApplication::setOrganizationName("MelkaJ");
QCoreApplication::setApplicationName("PDF4QT Document Diff");
QCoreApplication::setApplicationVersion(pdf::PDF_LIBRARY_VERSION);
QApplication::setApplicationDisplayName(QApplication::translate("Application", "PDF4QT Document Diff"));
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::applicationName());
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("file1", "The PDF file to be compared.");
parser.addPositionalArgument("file2", "The PDF file to be compared.");
parser.process(application);
pdfdocdiff::MainWindow mainWindow(nullptr);
mainWindow.show();
return application.exec();
}

View File

@ -1,880 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "aboutdialog.h"
#include "differencesdockwidget.h"
#include "settingsdockwidget.h"
#include "pdfwidgetutils.h"
#include "pdfdocumentreader.h"
#include "pdfdrawspacecontroller.h"
#include "pdfdocumentmanipulator.h"
#include "pdfdocumentbuilder.h"
#include "pdfdocumentwriter.h"
#include <QToolBar>
#include <QDesktopServices>
#include <QMessageBox>
#include <QInputDialog>
#include <QFileDialog>
#include <QVBoxLayout>
#include <QActionGroup>
#include <QScreen>
namespace pdfdocdiff
{
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_progress(new pdf::PDFProgress(this)),
#ifdef WIN_TASKBAR_BUTTON
m_taskbarButton(new QWinTaskbarButton(this)),
m_progressTaskbarIndicator(nullptr),
#endif
m_cmsManager(nullptr),
m_pdfWidget(nullptr),
m_settingsDockWidget(nullptr),
m_differencesDockWidget(nullptr),
m_optionalContentActivity(nullptr),
m_diff(nullptr),
m_isChangingProgressStep(false),
m_dontDisplayErrorMessage(false),
m_diffNavigator(nullptr),
m_drawInterface(&m_settings, &m_documentMapper, &m_filteredDiffResult)
{
ui->setupUi(this);
setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600)));
// Initialize task bar progress
#ifdef WIN_TASKBAR_BUTTON
m_progressTaskbarIndicator = m_taskbarButton->progress();
#endif
m_settingsDockWidget = new SettingsDockWidget(&m_settings, this);
addDockWidget(Qt::LeftDockWidgetArea, m_settingsDockWidget);;
connect(m_settingsDockWidget, &SettingsDockWidget::colorsChanged, this, &MainWindow::onColorsChanged);
connect(m_settingsDockWidget, &SettingsDockWidget::transparencySliderChanged, this, &MainWindow::updateOverlayTransparency);
m_differencesDockWidget = new DifferencesDockWidget(this, &m_diffResult, &m_filteredDiffResult, &m_diffNavigator, &m_settings);
addDockWidget(Qt::LeftDockWidgetArea, m_differencesDockWidget);
ui->documentFrame->setLayout(new QVBoxLayout);
m_cmsManager = new pdf::PDFCMSManager(this);
m_pdfWidget = new pdf::PDFWidget(m_cmsManager, pdf::RendererEngine::Software, 1, ui->documentFrame);
m_pdfWidget->getDrawWidgetProxy()->setProgress(m_progress);
ui->documentFrame->layout()->addWidget(m_pdfWidget);
m_pdfWidget->getDrawWidgetProxy()->registerDrawInterface(&m_drawInterface);
ui->menuView->addSeparator();
ui->menuView->addAction(m_settingsDockWidget->toggleViewAction());
ui->menuView->addAction(m_differencesDockWidget->toggleViewAction());
ui->actionGet_Source->setData(int(Operation::GetSource));
ui->actionAbout->setData(int(Operation::About));
ui->actionOpen_Left->setData(int(Operation::OpenLeft));
ui->actionOpen_Right->setData(int(Operation::OpenRight));
ui->actionCompare->setData(int(Operation::Compare));
ui->actionClose->setData(int(Operation::Close));
ui->actionPrevious_Difference->setData(int(Operation::PreviousDifference));
ui->actionNext_Difference->setData(int(Operation::NextDifference));
ui->actionCreate_Compare_Report->setData(int(Operation::CreateCompareReport));
ui->actionFilter_Text->setData(int(Operation::FilterText));
ui->actionFilter_Vector_Graphics->setData(int(Operation::FilterVectorGraphics));
ui->actionFilter_Images->setData(int(Operation::FilterImages));
ui->actionFilter_Shading->setData(int(Operation::FilterShading));
ui->actionFilter_Page_Movement->setData(int(Operation::FilterPageMovement));
ui->actionView_Differences->setData(int(Operation::ViewDifferences));
ui->actionView_Left->setData(int(Operation::ViewLeft));
ui->actionView_Right->setData(int(Operation::ViewRight));
ui->actionView_Overlay->setData(int(Operation::ViewOverlay));
ui->actionShow_Pages_with_Differences->setData(int(Operation::ShowPageswithDifferences));
ui->actionSave_Differences_to_XML->setData(int(Operation::SaveDifferencesToXML));
ui->actionDisplay_Differences->setData(int(Operation::DisplayDifferences));
ui->actionDisplay_Markers->setData(int(Operation::DisplayMarkers));
ui->actionSynchronize_View_with_Differences->setChecked(true);
QActionGroup* actionGroup = new QActionGroup(this);
actionGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive);
actionGroup->addAction(ui->actionView_Differences);
actionGroup->addAction(ui->actionView_Left);
actionGroup->addAction(ui->actionView_Right);
actionGroup->addAction(ui->actionView_Overlay);
ui->actionView_Differences->setChecked(true);
QToolBar* mainToolbar = addToolBar(tr("Main"));
mainToolbar->setObjectName("main_toolbar");
mainToolbar->addActions({ ui->actionOpen_Left, ui->actionOpen_Right });
mainToolbar->addSeparator();
mainToolbar->addAction(ui->actionCompare);
mainToolbar->addAction(ui->actionCreate_Compare_Report);
mainToolbar->addAction(ui->actionSave_Differences_to_XML);
QToolBar* differencesToolbar = addToolBar(tr("Differences"));
differencesToolbar->setObjectName("differences_toolbar");
differencesToolbar->addActions({ ui->actionPrevious_Difference, ui->actionNext_Difference });
QToolBar* viewToolbar = addToolBar(tr("View"));
viewToolbar->setObjectName("view_toolbar");
viewToolbar->addActions({ ui->actionView_Differences, ui->actionView_Left, ui->actionView_Right, ui->actionView_Overlay });
viewToolbar->addSeparator();
viewToolbar->addActions({ ui->actionShow_Pages_with_Differences, ui->actionSynchronize_View_with_Differences });
viewToolbar->addSeparator();
viewToolbar->addActions({ ui->actionFilter_Text, ui->actionFilter_Vector_Graphics, ui->actionFilter_Images, ui->actionFilter_Shading, ui->actionFilter_Page_Movement });
QSize iconSize = pdf::PDFWidgetUtils::scaleDPI(this, QSize(24, 24));
auto toolbars = findChildren<QToolBar*>();
for (QToolBar* toolbar : toolbars)
{
toolbar->setIconSize(iconSize);
ui->menuToolbars->addAction(toolbar->toggleViewAction());
}
connect(&m_mapper, &QSignalMapper::mappedInt, this, &MainWindow::onMappedActionTriggered);
QList<QAction*> actions = findChildren<QAction*>();
for (QAction* action : actions)
{
QVariant actionData = action->data();
if (actionData.isValid())
{
connect(action, &QAction::triggered, &m_mapper, QOverload<>::of(&QSignalMapper::map));
m_mapper.setMapping(action, actionData.toInt());
}
}
connect(m_progress, &pdf::PDFProgress::progressStarted, this, &MainWindow::onProgressStarted);
connect(m_progress, &pdf::PDFProgress::progressStep, this, &MainWindow::onProgressStep);
connect(m_progress, &pdf::PDFProgress::progressFinished, this, &MainWindow::onProgressFinished);
m_diff.setProgress(m_progress);
m_diff.setOption(pdf::PDFDiff::Asynchronous, true);
connect(&m_diff, &pdf::PDFDiff::comparationFinished, this, &MainWindow::onComparationFinished);
m_diff.setLeftDocument(&m_leftDocument);
m_diff.setRightDocument(&m_rightDocument);
m_diffNavigator.setResult(&m_filteredDiffResult);
connect(&m_diffNavigator, &pdf::PDFDiffResultNavigator::selectionChanged, this, &MainWindow::onSelectionChanged);
loadSettings();
updateAll(false);
updateOverlayTransparency();
}
MainWindow::~MainWindow()
{
saveSettings();
delete ui;
}
void MainWindow::showEvent(QShowEvent* event)
{
Q_UNUSED(event);
#ifdef WIN_TASKBAR_BUTTON
m_taskbarButton->setWindow(windowHandle());
#endif
}
void MainWindow::closeEvent(QCloseEvent* event)
{
BaseClass::closeEvent(event);
m_diff.stop();
}
void MainWindow::onMappedActionTriggered(int actionId)
{
performOperation(static_cast<Operation>(actionId));
}
void MainWindow::onComparationFinished()
{
clear(false, false);
m_diffResult = m_diff.getResult();
if (!m_dontDisplayErrorMessage)
{
if (!m_diffResult.getResult())
{
QMessageBox::critical(this, tr("Error"), m_diffResult.getResult().getErrorMessage());
}
if (m_diffResult.isSame())
{
QMessageBox::information(this, tr("Info"), tr("No differences found between the compared documents."), QMessageBox::Ok);
}
}
// Create merged document
pdf::PDFDocumentManipulator manipulator;
manipulator.setOutlineMode(pdf::PDFDocumentManipulator::OutlineMode::NoOutline);
manipulator.addDocument(1, &m_leftDocument);
manipulator.addDocument(2, &m_rightDocument);
pdf::PDFDocumentManipulator::AssembledPages assembledPages1 = pdf::PDFDocumentManipulator::createAllDocumentPages(1, &m_leftDocument);
pdf::PDFDocumentManipulator::AssembledPages assembledPages2 = pdf::PDFDocumentManipulator::createAllDocumentPages(2, &m_rightDocument);
assembledPages1.insert(assembledPages1.end(), std::make_move_iterator(assembledPages2.begin()), std::make_move_iterator(assembledPages2.end()));
if (manipulator.assemble(assembledPages1))
{
m_combinedDocument = manipulator.takeAssembledDocument();
}
else
{
m_combinedDocument = pdf::PDFDocument();
}
updateAll(true);
}
void MainWindow::onColorsChanged()
{
updateFilteredResult();
m_pdfWidget->update();
}
void MainWindow::updateActions()
{
QList<QAction*> actions = findChildren<QAction*>();
for (QAction* action : actions)
{
QVariant actionData = action->data();
if (actionData.isValid())
{
bool canPerformAction = canPerformOperation(static_cast<Operation>(actionData.toInt()));
action->setEnabled(canPerformAction);
if (!canPerformAction && action->isCheckable())
{
action->setChecked(false);
}
}
}
}
void MainWindow::onSelectionChanged(size_t currentIndex)
{
if (ui->actionSynchronize_View_with_Differences->isChecked())
{
pdf::PDFInteger destinationPage = -1;
if (destinationPage == -1)
{
pdf::PDFInteger leftPageIndex = m_filteredDiffResult.getLeftPage(currentIndex);
if (leftPageIndex != -1)
{
destinationPage = m_documentMapper.getPageIndexFromLeftPageIndex(leftPageIndex);
}
}
if (destinationPage == -1)
{
pdf::PDFInteger rightPageIndex = m_filteredDiffResult.getRightPage(currentIndex);
if (rightPageIndex != -1)
{
destinationPage = m_documentMapper.getPageIndexFromRightPageIndex(rightPageIndex);
}
}
if (destinationPage != -1)
{
m_pdfWidget->getDrawWidgetProxy()->goToPage(destinationPage);
}
}
updateActions();
}
void MainWindow::loadSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.beginGroup("MainWindow");
QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
if (geometry.isEmpty())
{
QRect availableGeometry = QApplication::primaryScreen()->availableGeometry();
QRect windowRect(0, 0, availableGeometry.width() / 2, availableGeometry.height() / 2);
windowRect = windowRect.translated(availableGeometry.center() - windowRect.center());
setGeometry(windowRect);
}
else
{
restoreGeometry(geometry);
}
QByteArray state = settings.value("windowState", QByteArray()).toByteArray();
if (!state.isEmpty())
{
restoreState(state);
}
settings.endGroup();
settings.beginGroup("Settings");
m_settings.directory = settings.value("directory").toString();
m_settings.colorPageMove = settings.value("colorPageMove", m_settings.colorPageMove).value<QColor>();
m_settings.colorAdded = settings.value("colorAdded", m_settings.colorAdded).value<QColor>();
m_settings.colorRemoved = settings.value("colorRemoved", m_settings.colorRemoved).value<QColor>();
m_settings.colorReplaced = settings.value("colorReplaced", m_settings.colorReplaced).value<QColor>();
m_settings.displayDifferences = settings.value("displayDifferences", m_settings.displayDifferences).toBool();
m_settings.displayMarkers = settings.value("displayMarkers", m_settings.displayDifferences).toBool();
settings.endGroup();
settings.beginGroup("Compare");
m_settingsDockWidget->setCompareTextsAsVectorGraphics(settings.value("compareTextsAsVectorGraphics", false).toBool());
m_settingsDockWidget->setCompareTextCharactersInsteadOfWords(settings.value("compareTextCharactersInsteadOfWords", false).toBool());
settings.endGroup();
ui->actionDisplay_Differences->setChecked(m_settings.displayDifferences);
ui->actionDisplay_Markers->setChecked(m_settings.displayMarkers);
m_settingsDockWidget->loadColors();
}
void MainWindow::saveSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.beginGroup("MainWindow");
settings.setValue("geometry", saveGeometry());
settings.setValue("windowState", saveState());
settings.endGroup();
settings.beginGroup("Settings");
settings.setValue("directory", m_settings.directory);
settings.setValue("colorPageMove", m_settings.colorPageMove);
settings.setValue("colorAdded", m_settings.colorAdded);
settings.setValue("colorRemoved", m_settings.colorRemoved);
settings.setValue("colorReplaced", m_settings.colorReplaced);
settings.setValue("displayDifferences", m_settings.displayDifferences);
settings.setValue("displayMarkers", m_settings.displayMarkers);
settings.endGroup();
settings.beginGroup("Compare");
settings.setValue("compareTextsAsVectorGraphics", m_settingsDockWidget->isCompareTextAsVectorGraphics());
settings.setValue("compareTextCharactersInsteadOfWords", m_settingsDockWidget->isCompareTextCharactersInsteadOfWords());
settings.endGroup();
}
bool MainWindow::canPerformOperation(Operation operation) const
{
switch (operation)
{
case Operation::OpenLeft:
case Operation::OpenRight:
case Operation::Compare:
case Operation::Close:
case Operation::GetSource:
case Operation::About:
return true;
case Operation::ViewDifferences:
case Operation::ViewLeft:
case Operation::ViewRight:
case Operation::ViewOverlay:
return true; // Allow always to change a view
case Operation::FilterText:
return m_diffResult.hasTextDifferences();
case Operation::FilterVectorGraphics:
return m_diffResult.hasVectorGraphicsDifferences();
case Operation::FilterImages:
return m_diffResult.hasImageDifferences();
case Operation::FilterShading:
return m_diffResult.hasShadingDifferences();
case Operation::FilterPageMovement:
return m_diffResult.hasPageMoveDifferences();
case Operation::PreviousDifference:
return m_diffNavigator.canGoPrevious();
case Operation::NextDifference:
return m_diffNavigator.canGoNext();
case Operation::CreateCompareReport:
case Operation::SaveDifferencesToXML:
return m_filteredDiffResult.isChanged();
case Operation::ShowPageswithDifferences:
return m_diffResult.isChanged();
case Operation::DisplayDifferences:
case Operation::DisplayMarkers:
return true;
default:
Q_ASSERT(false);
break;
}
return false;
}
void MainWindow::performOperation(Operation operation)
{
switch (operation)
{
case Operation::OpenLeft:
{
pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true);
m_diff.stop();
std::optional<pdf::PDFDocument> document = openDocument();
if (document)
{
clear(true, false);
m_leftDocument = std::move(*document);
const size_t pageCount = m_leftDocument.getCatalog()->getPageCount();
if (pageCount > 1)
{
m_settingsDockWidget->getLeftPageSelectionEdit()->setText(QString("1-%2").arg(pageCount));
}
else if (pageCount == 1)
{
m_settingsDockWidget->getLeftPageSelectionEdit()->setText("1");
}
else
{
m_settingsDockWidget->getLeftPageSelectionEdit()->clear();
}
updateViewDocument();
}
break;
}
case Operation::OpenRight:
{
pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true);
m_diff.stop();
std::optional<pdf::PDFDocument> document = openDocument();
if (document)
{
clear(false, true);
m_rightDocument = std::move(*document);
const size_t pageCount = m_rightDocument.getCatalog()->getPageCount();
if (pageCount > 1)
{
m_settingsDockWidget->getRightPageSelectionEdit()->setText(QString("1-%2").arg(pageCount));
}
else if (pageCount == 1)
{
m_settingsDockWidget->getRightPageSelectionEdit()->setText("1");
}
else
{
m_settingsDockWidget->getRightPageSelectionEdit()->clear();
}
updateViewDocument();
}
break;
}
case Operation::Compare:
{
pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true);
m_diff.stop();
m_diff.setOption(pdf::PDFDiff::CompareTextsAsVector, m_settingsDockWidget->isCompareTextAsVectorGraphics());
m_diff.setOption(pdf::PDFDiff::CompareWords, !m_settingsDockWidget->isCompareTextCharactersInsteadOfWords());
QString errorMessage;
pdf::PDFClosedIntervalSet rightPageIndices;
pdf::PDFClosedIntervalSet leftPageIndices = pdf::PDFClosedIntervalSet::parse(1, qMax<pdf::PDFInteger>(1, m_leftDocument.getCatalog()->getPageCount()), m_settingsDockWidget->getLeftPageSelectionEdit()->text(), &errorMessage);
if (errorMessage.isEmpty())
{
rightPageIndices = pdf::PDFClosedIntervalSet::parse(1, qMax<pdf::PDFInteger>(1, m_rightDocument.getCatalog()->getPageCount()), m_settingsDockWidget->getRightPageSelectionEdit()->text(), &errorMessage);
}
// Check if pages are succesfully parsed
if (!errorMessage.isEmpty())
{
QMessageBox::critical(this, tr("Error"), errorMessage);
break;
}
leftPageIndices.translate(-1);
rightPageIndices.translate(-1);
m_diff.setPagesForLeftDocument(std::move(leftPageIndices));
m_diff.setPagesForRightDocument(std::move(rightPageIndices));
m_diff.start();
break;
}
case Operation::Close:
{
close();
break;
}
case Operation::GetSource:
{
QDesktopServices::openUrl(QUrl("https://github.com/JakubMelka/PDF4QT"));
break;
}
case Operation::About:
{
PDFAboutDialog aboutDialog(this);
aboutDialog.exec();
break;
}
case Operation::PreviousDifference:
m_diffNavigator.goPrevious();
break;
case Operation::NextDifference:
m_diffNavigator.goNext();
break;
case Operation::FilterText:
case Operation::FilterVectorGraphics:
case Operation::FilterImages:
case Operation::FilterShading:
case Operation::FilterPageMovement:
{
updateFilteredResult();
if (ui->actionShow_Pages_with_Differences->isChecked())
{
updateCustomPageLayout();
}
break;
}
case Operation::ViewDifferences:
case Operation::ViewLeft:
case Operation::ViewRight:
case Operation::ViewOverlay:
updateViewDocument();
break;
case Operation::ShowPageswithDifferences:
updateCustomPageLayout();
break;
case Operation::DisplayDifferences:
m_settings.displayDifferences = ui->actionDisplay_Differences->isChecked();
m_pdfWidget->update();
break;
case Operation::DisplayMarkers:
m_settings.displayMarkers = ui->actionDisplay_Markers->isChecked();
m_pdfWidget->update();
break;
case Operation::SaveDifferencesToXML:
{
if (!m_filteredDiffResult.isSame())
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Select PDF document"), m_settings.directory, tr("XML file (*.xml)"));
if (!fileName.isEmpty())
{
QFile file(fileName);
if (file.open(QFile::WriteOnly | QFile::Truncate))
{
m_filteredDiffResult.saveToXML(&file);
file.close();
}
else
{
QMessageBox::critical(this, tr("Error"), tr("File '%1' cannot be opened. %2").arg(fileName, file.errorString()));
}
}
}
else
{
QMessageBox::information(this, tr("Save results to XML"), tr("Displayed results are empty. Cannot save empty results."));
}
break;
}
case Operation::CreateCompareReport:
{
if (m_filteredDiffResult.isSame())
{
break;
}
QString saveFileName = QFileDialog::getSaveFileName(this, tr("Save As"), m_settings.directory, tr("Portable Document (*.pdf);;All files (*.*)"));
if (!saveFileName.isEmpty())
{
pdf::PDFDocumentBuilder builder(m_pdfWidget->getDrawWidgetProxy()->getDocument());
m_drawInterface.drawAnnotations(m_pdfWidget->getDrawWidgetProxy()->getDocument(), &builder);
pdf::PDFDocument document = builder.build();
pdf::PDFDocumentWriter writer(m_progress);
pdf::PDFOperationResult result = writer.write(saveFileName, &document, QFile::exists(saveFileName));
if (!result)
{
QMessageBox::critical(this, tr("Error"), result.getErrorMessage());
}
}
break;
}
default:
{
Q_ASSERT(false);
break;
}
}
updateActions();
}
void MainWindow::setViewDocument(pdf::PDFDocument* document, bool updateCustomPageLayout)
{
if (document != m_pdfWidget->getDrawWidgetProxy()->getDocument())
{
m_optionalContentActivity->deleteLater();
m_optionalContentActivity = nullptr;
if (document)
{
m_optionalContentActivity = new pdf::PDFOptionalContentActivity(document, pdf::OCUsage::View, this);
}
if (document)
{
pdf::PDFModifiedDocument modifiedDocument(document, m_optionalContentActivity);
m_pdfWidget->setDocument(modifiedDocument);
}
else
{
m_pdfWidget->setDocument(pdf::PDFModifiedDocument());
}
}
if (updateCustomPageLayout)
{
this->updateCustomPageLayout();
}
}
ComparedDocumentMapper::Mode MainWindow::getDocumentViewMode() const
{
if (ui->actionView_Left->isChecked())
{
return ComparedDocumentMapper::Mode::Left;
}
if (ui->actionView_Right->isChecked())
{
return ComparedDocumentMapper::Mode::Right;
}
if (ui->actionView_Overlay->isChecked())
{
return ComparedDocumentMapper::Mode::Overlay;
}
return ComparedDocumentMapper::Mode::Combined;
}
void MainWindow::clear(bool clearLeftDocument, bool clearRightDocument)
{
setViewDocument(nullptr, true);
if (clearLeftDocument)
{
m_leftDocument = pdf::PDFDocument();
m_settingsDockWidget->getLeftPageSelectionEdit()->clear();
}
if (clearRightDocument)
{
m_rightDocument = pdf::PDFDocument();
m_settingsDockWidget->getRightPageSelectionEdit()->clear();
}
m_diffResult = pdf::PDFDiffResult();
m_filteredDiffResult = pdf::PDFDiffResult();
m_diffNavigator.update();
updateAll(false);
}
void MainWindow::updateAll(bool resetFilters)
{
if (resetFilters)
{
ui->actionFilter_Page_Movement->setChecked(m_diffResult.hasPageMoveDifferences());
ui->actionFilter_Text->setChecked(m_diffResult.hasTextDifferences());
ui->actionFilter_Vector_Graphics->setChecked(m_diffResult.hasVectorGraphicsDifferences());
ui->actionFilter_Images->setChecked(m_diffResult.hasImageDifferences());
ui->actionFilter_Shading->setChecked(m_diffResult.hasShadingDifferences());
}
updateFilteredResult();
updateViewDocument();
}
void MainWindow::updateFilteredResult()
{
m_filteredDiffResult = m_diffResult.filter(ui->actionFilter_Page_Movement->isChecked(),
ui->actionFilter_Text->isChecked(),
ui->actionFilter_Vector_Graphics->isChecked(),
ui->actionFilter_Images->isChecked(),
ui->actionFilter_Shading->isChecked());
m_diffNavigator.update();
if (m_differencesDockWidget)
{
m_differencesDockWidget->update();
}
updateActions();
}
void MainWindow::updateViewDocument()
{
pdf::PDFDocument* document = nullptr;
switch (getDocumentViewMode())
{
case ComparedDocumentMapper::Mode::Left:
document = &m_leftDocument;
break;
case ComparedDocumentMapper::Mode::Right:
document = &m_rightDocument;
break;
case ComparedDocumentMapper::Mode::Combined:
case ComparedDocumentMapper::Mode::Overlay:
document = &m_combinedDocument;
break;
}
setViewDocument(document, true);
}
void MainWindow::updateCustomPageLayout()
{
m_documentMapper.update(getDocumentViewMode(),
ui->actionShow_Pages_with_Differences->isChecked(),
m_filteredDiffResult,
&m_leftDocument,
&m_rightDocument,
m_pdfWidget->getDrawWidgetProxy()->getDocument());
m_pdfWidget->getDrawWidgetProxy()->setCustomPageLayout(m_documentMapper.getLayout());
m_pdfWidget->getDrawWidgetProxy()->setPageLayout(pdf::PageLayout::Custom);
}
void MainWindow::updateOverlayTransparency()
{
const pdf::PDFReal value = m_settingsDockWidget->getTransparencySliderValue() * 0.01;
m_pdfWidget->getDrawWidgetProxy()->setGroupTransparency(1, true, 1.0 - value);
m_pdfWidget->getDrawWidgetProxy()->setGroupTransparency(2, false, value);
m_pdfWidget->update();
}
std::optional<pdf::PDFDocument> MainWindow::openDocument()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)"));
if (fileName.isEmpty())
{
return std::nullopt;
}
auto queryPassword = [this](bool* ok)
{
*ok = false;
return QInputDialog::getText(this, tr("Encrypted document"), tr("Enter password to access document content"), QLineEdit::Password, QString(), ok);
};
// Mark current directory as this
QFileInfo fileInfo(fileName);
m_settings.directory = fileInfo.dir().absolutePath();
// Try to open a new document
pdf::PDFDocumentReader reader(nullptr, qMove(queryPassword), true, false);
pdf::PDFDocument document = reader.readFromFile(fileName);
QString errorMessage = reader.getErrorMessage();
pdf::PDFDocumentReader::Result result = reader.getReadingResult();
if (result == pdf::PDFDocumentReader::Result::OK)
{
return document;
}
else if (result == pdf::PDFDocumentReader::Result::Failed)
{
QMessageBox::critical(this, tr("Error"), errorMessage);
}
return pdf::PDFDocument();
}
void MainWindow::onProgressStarted(pdf::ProgressStartupInfo info)
{
#ifdef WIN_TASKBAR_BUTTON
m_progressTaskbarIndicator->setRange(0, 100);
m_progressTaskbarIndicator->reset();
m_progressTaskbarIndicator->show();
#else
Q_UNUSED(info);
#endif
}
void MainWindow::onProgressStep(int percentage)
{
if (m_isChangingProgressStep)
{
return;
}
pdf::PDFTemporaryValueChange guard(&m_isChangingProgressStep, true);
#ifdef WIN_TASKBAR_BUTTON
m_progressTaskbarIndicator->setValue(percentage);
#else
Q_UNUSED(percentage);
#endif
}
void MainWindow::onProgressFinished()
{
#ifdef WIN_TASKBAR_BUTTON
m_progressTaskbarIndicator->hide();
#endif
}
} // namespace pdfdocdiff

View File

@ -1,155 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDOCDIFF_MAINWINDOW_H
#define PDFDOCDIFF_MAINWINDOW_H
#include "utils.h"
#include "pdfdocument.h"
#include "pdfdrawwidget.h"
#include "pdfcms.h"
#include "pdfoptionalcontent.h"
#include <QMainWindow>
#include <QSignalMapper>
#ifdef WIN_TASKBAR_BUTTON
#include <QWinTaskbarButton>
#include <QWinTaskbarProgress>
#endif
namespace Ui
{
class MainWindow;
}
namespace pdfdocdiff
{
class SettingsDockWidget;
class DifferencesDockWidget;
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
using BaseClass = QMainWindow;
public:
explicit MainWindow(QWidget* parent);
virtual ~MainWindow() override;
enum class Operation
{
OpenLeft,
OpenRight,
Compare,
Close,
GetSource,
About,
PreviousDifference,
NextDifference,
CreateCompareReport,
FilterText,
FilterVectorGraphics,
FilterImages,
FilterShading,
FilterPageMovement,
ViewDifferences,
ViewLeft,
ViewRight,
ViewOverlay,
ShowPageswithDifferences,
SaveDifferencesToXML,
DisplayDifferences,
DisplayMarkers
};
virtual void showEvent(QShowEvent* event) override;
virtual void closeEvent(QCloseEvent* event) override;
private slots:
void updateActions();
void onSelectionChanged(size_t currentIndex);
private:
void onMappedActionTriggered(int actionId);
void onComparationFinished();
void onColorsChanged();
void onProgressStarted(pdf::ProgressStartupInfo info);
void onProgressStep(int percentage);
void onProgressFinished();
void loadSettings();
void saveSettings();
bool canPerformOperation(Operation operation) const;
void performOperation(Operation operation);
void setViewDocument(pdf::PDFDocument* document, bool updateCustomPageLayout);
ComparedDocumentMapper::Mode getDocumentViewMode() const;
/// Clears all data, and possibly documents also.
/// View document is set to nullptr.
/// \param clearLeftDocument Clear left document?
/// \param clearRightDocument Clear left document?
void clear(bool clearLeftDocument, bool clearRightDocument);
void updateAll(bool resetFilters);
void updateFilteredResult();
void updateViewDocument();
void updateCustomPageLayout();
void updateOverlayTransparency();
std::optional<pdf::PDFDocument> openDocument();
Ui::MainWindow* ui;
pdf::PDFProgress* m_progress;
#ifdef WIN_TASKBAR_BUTTON
QWinTaskbarButton* m_taskbarButton;
QWinTaskbarProgress* m_progressTaskbarIndicator;
#endif
pdf::PDFCMSManager* m_cmsManager;
pdf::PDFWidget* m_pdfWidget;
SettingsDockWidget* m_settingsDockWidget;
DifferencesDockWidget* m_differencesDockWidget;
pdf::PDFOptionalContentActivity* m_optionalContentActivity;
Settings m_settings;
QSignalMapper m_mapper;
pdf::PDFDiff m_diff;
bool m_isChangingProgressStep;
bool m_dontDisplayErrorMessage;
pdf::PDFDocument m_leftDocument;
pdf::PDFDocument m_rightDocument;
pdf::PDFDocument m_combinedDocument;
pdf::PDFDiffResult m_diffResult;
pdf::PDFDiffResult m_filteredDiffResult; ///< Difference result with filters applied
pdf::PDFDiffResultNavigator m_diffNavigator; ///< Difference navigator
ComparedDocumentMapper m_documentMapper;
DifferencesDrawInterface m_drawInterface;
};
} // namespace pdfdocdiff
#endif // PDFDOCDIFF_MAINWINDOW_H

View File

@ -1,370 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>864</width>
<height>638</height>
</rect>
</property>
<property name="windowTitle">
<string>Workspace</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout" rowstretch="0">
<item row="0" column="0" colspan="2">
<widget class="QFrame" name="documentFrame"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>864</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionOpen_Left"/>
<addaction name="actionOpen_Right"/>
<addaction name="actionClose"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="actionGet_Source"/>
<addaction name="actionAbout"/>
</widget>
<widget class="QMenu" name="menuToolbars">
<property name="title">
<string>Toolbars</string>
</property>
</widget>
<widget class="QMenu" name="menuCompare">
<property name="title">
<string>Compare</string>
</property>
<addaction name="actionCompare"/>
<addaction name="actionCreate_Compare_Report"/>
<addaction name="actionSave_Differences_to_XML"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>View</string>
</property>
<widget class="QMenu" name="menuView_2">
<property name="title">
<string>View</string>
</property>
<addaction name="actionView_Differences"/>
<addaction name="actionView_Left"/>
<addaction name="actionView_Right"/>
<addaction name="actionView_Overlay"/>
</widget>
<widget class="QMenu" name="menuFilter">
<property name="title">
<string>Filter</string>
</property>
<addaction name="actionFilter_Text"/>
<addaction name="actionFilter_Vector_Graphics"/>
<addaction name="actionFilter_Images"/>
<addaction name="actionFilter_Shading"/>
<addaction name="actionFilter_Page_Movement"/>
</widget>
<addaction name="actionPrevious_Difference"/>
<addaction name="actionNext_Difference"/>
<addaction name="separator"/>
<addaction name="menuView_2"/>
<addaction name="menuFilter"/>
<addaction name="actionShow_Pages_with_Differences"/>
<addaction name="actionSynchronize_View_with_Differences"/>
<addaction name="separator"/>
<addaction name="actionDisplay_Differences"/>
<addaction name="actionDisplay_Markers"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuView"/>
<addaction name="menuCompare"/>
<addaction name="menuToolbars"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionGet_Source">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/get-source.svg</normaloff>:/pdfdocdiff/resources/get-source.svg</iconset>
</property>
<property name="text">
<string>Get Source</string>
</property>
</action>
<action name="actionAbout">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/about.svg</normaloff>:/pdfdocdiff/resources/about.svg</iconset>
</property>
<property name="text">
<string>About...</string>
</property>
<property name="shortcut">
<string>F1</string>
</property>
</action>
<action name="actionOpen_Left">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/open-left.svg</normaloff>:/pdfdocdiff/resources/open-left.svg</iconset>
</property>
<property name="text">
<string>Open Left...</string>
</property>
</action>
<action name="actionOpen_Right">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/open-right.svg</normaloff>:/pdfdocdiff/resources/open-right.svg</iconset>
</property>
<property name="text">
<string>Open Right...</string>
</property>
</action>
<action name="actionCompare">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/compare.svg</normaloff>:/pdfdocdiff/resources/compare.svg</iconset>
</property>
<property name="text">
<string>Compare</string>
</property>
<property name="shortcut">
<string>F5</string>
</property>
</action>
<action name="actionClose">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/close.svg</normaloff>:/pdfdocdiff/resources/close.svg</iconset>
</property>
<property name="text">
<string>Close</string>
</property>
<property name="shortcut">
<string>Ctrl+F4</string>
</property>
</action>
<action name="actionPrevious_Difference">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/prev-diff.svg</normaloff>:/pdfdocdiff/resources/prev-diff.svg</iconset>
</property>
<property name="text">
<string>Previous Difference</string>
</property>
<property name="shortcut">
<string>Shift+F6</string>
</property>
</action>
<action name="actionNext_Difference">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/next-diff.svg</normaloff>:/pdfdocdiff/resources/next-diff.svg</iconset>
</property>
<property name="text">
<string>Next Difference</string>
</property>
<property name="shortcut">
<string>F6</string>
</property>
</action>
<action name="actionCreate_Compare_Report">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/create-compare-report.svg</normaloff>:/pdfdocdiff/resources/create-compare-report.svg</iconset>
</property>
<property name="text">
<string>Create Compare Report...</string>
</property>
</action>
<action name="actionFilter_Text">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/filter-text.svg</normaloff>:/pdfdocdiff/resources/filter-text.svg</iconset>
</property>
<property name="text">
<string>Filter Text</string>
</property>
</action>
<action name="actionFilter_Vector_Graphics">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/filter-vector-graphics.svg</normaloff>:/pdfdocdiff/resources/filter-vector-graphics.svg</iconset>
</property>
<property name="text">
<string>Filter Vector Graphics</string>
</property>
</action>
<action name="actionFilter_Images">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/filter-images.svg</normaloff>:/pdfdocdiff/resources/filter-images.svg</iconset>
</property>
<property name="text">
<string>Filter Images</string>
</property>
</action>
<action name="actionFilter_Shading">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/filter-shading.svg</normaloff>:/pdfdocdiff/resources/filter-shading.svg</iconset>
</property>
<property name="text">
<string>Filter Shading</string>
</property>
</action>
<action name="actionFilter_Page_Movement">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/filter-page-movement.svg</normaloff>:/pdfdocdiff/resources/filter-page-movement.svg</iconset>
</property>
<property name="text">
<string>Filter Page Movement</string>
</property>
</action>
<action name="actionView_Differences">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/view-differences.svg</normaloff>:/pdfdocdiff/resources/view-differences.svg</iconset>
</property>
<property name="text">
<string>View Differences</string>
</property>
</action>
<action name="actionView_Left">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/view-left.svg</normaloff>:/pdfdocdiff/resources/view-left.svg</iconset>
</property>
<property name="text">
<string>View Left</string>
</property>
</action>
<action name="actionView_Right">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/view-right.svg</normaloff>:/pdfdocdiff/resources/view-right.svg</iconset>
</property>
<property name="text">
<string>View Right</string>
</property>
</action>
<action name="actionView_Overlay">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/view-overlay.svg</normaloff>:/pdfdocdiff/resources/view-overlay.svg</iconset>
</property>
<property name="text">
<string>View Overlay</string>
</property>
</action>
<action name="actionShow_Pages_with_Differences">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/show-p-with-diff.svg</normaloff>:/pdfdocdiff/resources/show-p-with-diff.svg</iconset>
</property>
<property name="text">
<string>Show Pages with Differences</string>
</property>
<property name="toolTip">
<string>Show Pages with Differences</string>
</property>
</action>
<action name="actionSave_Differences_to_XML">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/save-diff-to-xml.svg</normaloff>:/pdfdocdiff/resources/save-diff-to-xml.svg</iconset>
</property>
<property name="text">
<string>Save Differences to XML...</string>
</property>
</action>
<action name="actionSynchronize_View_with_Differences">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/synchronize-view.svg</normaloff>:/pdfdocdiff/resources/synchronize-view.svg</iconset>
</property>
<property name="text">
<string>Synchronize View with Differences</string>
</property>
</action>
<action name="actionDisplay_Differences">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/display-differences.svg</normaloff>:/pdfdocdiff/resources/display-differences.svg</iconset>
</property>
<property name="text">
<string>Display Differences</string>
</property>
</action>
<action name="actionDisplay_Markers">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/pdfdocdiff/resources/display-markers.svg</normaloff>:/pdfdocdiff/resources/display-markers.svg</iconset>
</property>
<property name="text">
<string>Display Markers</string>
</property>
</action>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -1,27 +0,0 @@
<RCC>
<qresource prefix="/pdfdocdiff">
<file>resources/about.svg</file>
<file>resources/close.svg</file>
<file>resources/compare.svg</file>
<file>resources/get-source.svg</file>
<file>resources/open-left.svg</file>
<file>resources/open-right.svg</file>
<file>resources/create-compare-report.svg</file>
<file>resources/filter-images.svg</file>
<file>resources/filter-page-movement.svg</file>
<file>resources/filter-shading.svg</file>
<file>resources/filter-text.svg</file>
<file>resources/filter-vector-graphics.svg</file>
<file>resources/next-diff.svg</file>
<file>resources/prev-diff.svg</file>
<file>resources/save-diff-to-xml.svg</file>
<file>resources/show-p-with-diff.svg</file>
<file>resources/synchronize-view.svg</file>
<file>resources/view-differences.svg</file>
<file>resources/view-left.svg</file>
<file>resources/view-overlay.svg</file>
<file>resources/view-right.svg</file>
<file>resources/display-differences.svg</file>
<file>resources/display-markers.svg</file>
</qresource>
</RCC>

View File

@ -1,40 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QColor>
namespace pdfdocdiff
{
struct Settings
{
QString directory;
QColor colorPageMove = QColor(35, 145, 255);
QColor colorAdded = QColor(125, 250, 0);
QColor colorRemoved = QColor(255, 50, 50);
QColor colorReplaced = QColor(255, 120, 30);
bool displayDifferences = true;
bool displayMarkers = true;
};
} // namespace pdfdocdiff
#endif // SETTINGS_H

View File

@ -1,150 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "settingsdockwidget.h"
#include "ui_settingsdockwidget.h"
#include "pdfutils.h"
#include "pdfwidgetutils.h"
namespace pdfdocdiff
{
SettingsDockWidget::SettingsDockWidget(Settings* settings, QWidget* parent) :
QDockWidget(parent),
ui(new Ui::SettingsDockWidget),
m_settings(settings),
m_loadingColors(false)
{
ui->setupUi(this);
auto colorNames = QColor::colorNames();
for (QComboBox* comboBox : findChildren<QComboBox*>())
{
for (const QString& colorName : colorNames)
{
QColor color(colorName);
comboBox->addItem(getIconForColor(color), colorName, color);
}
connect(comboBox, &QComboBox::editTextChanged, this, &SettingsDockWidget::onEditColorChanged);
}
connect(ui->transparencySlider, &QSlider::valueChanged, this, &SettingsDockWidget::transparencySliderChanged);
}
SettingsDockWidget::~SettingsDockWidget()
{
delete ui;
}
void SettingsDockWidget::setCompareTextsAsVectorGraphics(bool enabled)
{
ui->compareTextsAsVectorGraphicsCheckBox->setChecked(enabled);
}
bool SettingsDockWidget::isCompareTextAsVectorGraphics() const
{
return ui->compareTextsAsVectorGraphicsCheckBox->isChecked();
}
void SettingsDockWidget::setCompareTextCharactersInsteadOfWords(bool enabled)
{
ui->compareCharactersInsteadOfWordsCheckBox->setChecked(enabled);
}
bool SettingsDockWidget::isCompareTextCharactersInsteadOfWords() const
{
return ui->compareCharactersInsteadOfWordsCheckBox->isChecked();
}
QLineEdit* SettingsDockWidget::getLeftPageSelectionEdit() const
{
return ui->leftPageSelectionEdit;
}
QLineEdit* SettingsDockWidget::getRightPageSelectionEdit() const
{
return ui->rightPageSelectionEdit;
}
void SettingsDockWidget::loadColors()
{
pdf::PDFTemporaryValueChange guard(&m_loadingColors, true);
auto loadColor = [](QComboBox* comboBox, QColor color)
{
auto index = comboBox->findData(color);
comboBox->setCurrentIndex(index);
if (index == -1)
{
comboBox->setCurrentText(color.name());
}
};
loadColor(ui->removeColorCombo, m_settings->colorRemoved);
loadColor(ui->addColorCombo, m_settings->colorAdded);
loadColor(ui->replaceColorCombo, m_settings->colorReplaced);
loadColor(ui->moveColorCombo, m_settings->colorPageMove);
}
int SettingsDockWidget::getTransparencySliderValue() const
{
return ui->transparencySlider->value();
}
QIcon SettingsDockWidget::getIconForColor(QColor color) const
{
QIcon icon;
QSize iconSize = pdf::PDFWidgetUtils::scaleDPI(this, QSize(16, 16));
QPixmap pixmap(iconSize.width(), iconSize.height());
pixmap.fill(color);
icon.addPixmap(pixmap);
return icon;
}
void SettingsDockWidget::onEditColorChanged()
{
if (m_loadingColors)
{
return;
}
bool isChanged = false;
auto saveColor = [&isChanged](QComboBox* comboBox, QColor& color)
{
QColor oldColor = color;
color.setNamedColor(comboBox->currentText());
isChanged = isChanged || oldColor != color;
};
saveColor(ui->removeColorCombo, m_settings->colorRemoved);
saveColor(ui->addColorCombo, m_settings->colorAdded);
saveColor(ui->replaceColorCombo, m_settings->colorReplaced);
saveColor(ui->moveColorCombo, m_settings->colorPageMove);
if (isChanged)
{
Q_EMIT colorsChanged();
}
}
} // namespace pdfdocdiff

View File

@ -1,73 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef SETTINGSDOCKWIDGET_H
#define SETTINGSDOCKWIDGET_H
#include "settings.h"
#include <QDockWidget>
namespace Ui
{
class SettingsDockWidget;
}
class QLineEdit;
namespace pdfdocdiff
{
class SettingsDockWidget : public QDockWidget
{
Q_OBJECT
public:
explicit SettingsDockWidget(Settings* settings, QWidget* parent);
virtual ~SettingsDockWidget() override;
void setCompareTextsAsVectorGraphics(bool enabled);
bool isCompareTextAsVectorGraphics() const;
void setCompareTextCharactersInsteadOfWords(bool enabled);
bool isCompareTextCharactersInsteadOfWords() const;
QLineEdit* getLeftPageSelectionEdit() const;
QLineEdit* getRightPageSelectionEdit() const;
void loadColors();
void saveColors();
int getTransparencySliderValue() const;
signals:
void colorsChanged();
void transparencySliderChanged(int value);
private:
QIcon getIconForColor(QColor color) const;
void onEditColorChanged();
Ui::SettingsDockWidget* ui;
Settings* m_settings;
bool m_loadingColors;
};
} // namespace pdfdocdiff
#endif // SETTINGSDOCKWIDGET_H

View File

@ -1,563 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "utils.h"
#include "pdfutils.h"
#include "pdfwidgetutils.h"
#include "pdfpainterutils.h"
#include "pdfdocumentbuilder.h"
#include <QPainter>
namespace pdfdocdiff
{
void ComparedDocumentMapper::update(ComparedDocumentMapper::Mode mode,
bool filterDifferences,
const pdf::PDFDiffResult& diff,
const pdf::PDFDocument* leftDocument,
const pdf::PDFDocument* rightDocument,
const pdf::PDFDocument* currentDocument)
{
m_layout.clear();
m_leftPageIndices.clear();
m_rightPageIndices.clear();
m_allLeft = false;
m_allRight = false;
if (!leftDocument || !rightDocument || !currentDocument)
{
return;
}
// Jakub Melka
pdf::PDFDiffResult::PageSequence pageSequence = diff.getPageSequence();
const bool isEmpty = pageSequence.empty();
if (filterDifferences)
{
pdf::PDFDiffResult::PageSequence filteredPageSequence;
std::vector<pdf::PDFInteger> leftPageIndices = diff.getChangedLeftPageIndices();
std::vector<pdf::PDFInteger> rightPageIndices = diff.getChangedRightPageIndices();
for (const pdf::PDFDiffResult::PageSequenceItem& item : pageSequence)
{
const bool isLeftModified = std::binary_search(leftPageIndices.cbegin(), leftPageIndices.cend(), item.leftPage);
const bool isRightModified = std::binary_search(rightPageIndices.cbegin(), rightPageIndices.cend(), item.rightPage);
if (isLeftModified || isRightModified)
{
filteredPageSequence.push_back(item);
}
}
pageSequence = std::move(filteredPageSequence);
}
switch (mode)
{
case ComparedDocumentMapper::Mode::Left:
{
Q_ASSERT(leftDocument == currentDocument);
m_allLeft = true;
double yPos = 0.0;
const pdf::PDFCatalog* catalog = leftDocument->getCatalog();
if (isEmpty)
{
// Just copy all pages
const size_t pageCount = catalog->getPageCount();
for (size_t i = 0; i < pageCount; ++i)
{
QSizeF pageSize = catalog->getPage(i)->getRotatedMediaBoxMM().size();
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
m_layout.emplace_back(0, i, -1, rect);
yPos += pageSize.height() + 5;
}
}
else
{
for (const pdf::PDFDiffResult::PageSequenceItem& item : pageSequence)
{
if (item.leftPage == -1)
{
continue;
}
QSizeF pageSize = catalog->getPage(item.leftPage)->getRotatedMediaBoxMM().size();
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
m_layout.emplace_back(0, item.leftPage, -1, rect);
yPos += pageSize.height() + 5;
}
}
break;
}
case ComparedDocumentMapper::Mode::Right:
{
Q_ASSERT(rightDocument == currentDocument);
m_allRight = true;
double yPos = 0.0;
const pdf::PDFCatalog* catalog = rightDocument->getCatalog();
if (isEmpty)
{
// Just copy all pages
const size_t pageCount = catalog->getPageCount();
for (size_t i = 0; i < pageCount; ++i)
{
QSizeF pageSize = catalog->getPage(i)->getRotatedMediaBoxMM().size();
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
m_layout.emplace_back(0, i, -1, rect);
yPos += pageSize.height() + 5;
}
}
else
{
for (const pdf::PDFDiffResult::PageSequenceItem& item : pageSequence)
{
if (item.rightPage == -1)
{
continue;
}
QSizeF pageSize = catalog->getPage(item.rightPage)->getRotatedMediaBoxMM().size();
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
m_layout.emplace_back(0, item.rightPage, -1, rect);
yPos += pageSize.height() + 5;
}
}
break;
}
case ComparedDocumentMapper::Mode::Combined:
case ComparedDocumentMapper::Mode::Overlay:
{
double yPos = 0.0;
const pdf::PDFCatalog* catalog = currentDocument->getCatalog();
pdf::PDFInteger offset = leftDocument->getCatalog()->getPageCount();
for (const pdf::PDFDiffResult::PageSequenceItem& item : pageSequence)
{
double yAdvance = 0.0;
if (item.leftPage != -1)
{
QSizeF pageSize = catalog->getPage(item.leftPage)->getRotatedMediaBoxMM().size();
QRectF rect;
pdf::PDFInteger groupIndex = -1;
if (mode == ComparedDocumentMapper::Mode::Combined)
{
rect = QRectF(-pageSize.width() - 5, yPos, pageSize.width(), pageSize.height());
}
else
{
if (item.rightPage != -1)
{
groupIndex = 1;
}
rect = QRectF(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
}
m_layout.emplace_back(0, item.leftPage, groupIndex, rect);
yAdvance = pageSize.height() + 5;
m_leftPageIndices[item.leftPage] = item.leftPage;
}
if (item.rightPage != -1)
{
pdf::PDFInteger rightPageIndex = item.rightPage + offset;
QSizeF pageSize = catalog->getPage(rightPageIndex)->getRotatedMediaBoxMM().size();
QRectF rect;
pdf::PDFInteger groupIndex = -1;
if (mode == ComparedDocumentMapper::Mode::Combined)
{
rect = QRectF(5, yPos, pageSize.width(), pageSize.height());
}
else
{
if (item.leftPage != -1)
{
groupIndex = 2;
}
rect = QRectF(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
}
m_layout.emplace_back(0, rightPageIndex, groupIndex, rect);
yAdvance = qMax(yAdvance, pageSize.height() + 5);
m_rightPageIndices[rightPageIndex] = item.rightPage;
}
yPos += yAdvance;
}
break;
}
default:
Q_ASSERT(false);
break;
}
}
pdf::PDFInteger ComparedDocumentMapper::getLeftPageIndex(pdf::PDFInteger pageIndex) const
{
if (m_allLeft)
{
return pageIndex;
}
auto it = m_leftPageIndices.find(pageIndex);
if (it != m_leftPageIndices.cend())
{
return it->second;
}
return -1;
}
pdf::PDFInteger ComparedDocumentMapper::getRightPageIndex(pdf::PDFInteger pageIndex) const
{
if (m_allRight)
{
return pageIndex;
}
auto it = m_rightPageIndices.find(pageIndex);
if (it != m_rightPageIndices.cend())
{
return it->second;
}
return -1;
}
pdf::PDFInteger ComparedDocumentMapper::getPageIndexFromLeftPageIndex(pdf::PDFInteger leftPageIndex) const
{
if (m_allLeft)
{
return leftPageIndex;
}
for (const auto& indexItem : m_leftPageIndices)
{
if (indexItem.second == leftPageIndex)
{
return indexItem.first;
}
}
return -1;
}
pdf::PDFInteger ComparedDocumentMapper::getPageIndexFromRightPageIndex(pdf::PDFInteger rightPageIndex) const
{
if (m_allRight)
{
return rightPageIndex;
}
for (const auto& indexItem : m_rightPageIndices)
{
if (indexItem.second == rightPageIndex)
{
return indexItem.first;
}
}
return -1;
}
DifferencesDrawInterface::DifferencesDrawInterface(const Settings* settings,
const ComparedDocumentMapper* mapper,
const pdf::PDFDiffResult* diffResult) :
m_settings(settings),
m_mapper(mapper),
m_diffResult(diffResult)
{
}
void DifferencesDrawInterface::drawPage(QPainter* painter,
pdf::PDFInteger pageIndex,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
QList<pdf::PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
if (!m_settings->displayDifferences)
{
return;
}
const size_t differencesCount = m_diffResult->getDifferencesCount();
const pdf::PDFInteger leftPageIndex = m_mapper->getLeftPageIndex(pageIndex);
const pdf::PDFInteger rightPageIndex = m_mapper->getRightPageIndex(pageIndex);
std::optional<size_t> pageMoveIndex;
if (leftPageIndex != -1)
{
for (size_t i = 0; i < differencesCount; ++i)
{
auto leftRectangles = m_diffResult->getLeftRectangles(i);
for (auto it = leftRectangles.first; it != leftRectangles.second; ++it)
{
const auto& item = *it;
if (item.first == leftPageIndex)
{
QColor color = getColorForIndex(i);
drawRectangle(painter, pagePointToDevicePointMatrix, item.second, color);
drawMarker(painter, pagePointToDevicePointMatrix, item.second, color, true);
}
}
if (m_diffResult->isPageMoveAddRemoveDifference(i) && m_diffResult->getLeftPage(i) == leftPageIndex)
{
pageMoveIndex = i;
}
}
}
if (rightPageIndex != -1)
{
for (size_t i = 0; i < differencesCount; ++i)
{
auto rightRectangles = m_diffResult->getRightRectangles(i);
for (auto it = rightRectangles.first; it != rightRectangles.second; ++it)
{
const auto& item = *it;
if (item.first == rightPageIndex)
{
QColor color = getColorForIndex(i);
drawRectangle(painter, pagePointToDevicePointMatrix, item.second, color);
drawMarker(painter, pagePointToDevicePointMatrix, item.second, color, false);
}
}
if (m_diffResult->isPageMoveAddRemoveDifference(i) && m_diffResult->getRightPage(i) == rightPageIndex)
{
pageMoveIndex = i;
}
}
}
if (pageMoveIndex)
{
QString text;
switch (m_diffResult->getType(*pageMoveIndex))
{
case pdf::PDFDiffResult::Type::PageAdded:
text = " + ";
break;
case pdf::PDFDiffResult::Type::PageRemoved:
text = " - ";
break;
case pdf::PDFDiffResult::Type::PageMoved:
text = QString("%1🠖%2").arg(m_diffResult->getLeftPage(*pageMoveIndex) + 1).arg(m_diffResult->getRightPage(*pageMoveIndex) + 1);
break;
default:
Q_ASSERT(false);
break;
}
QColor color = getColorForIndex(*pageMoveIndex);
QPointF targetPoint = pagePointToDevicePointMatrix.map(QPointF(5, 5));
pdf::PDFPainterHelper::drawBubble(painter, targetPoint.toPoint(), color, text, Qt::AlignRight | Qt::AlignTop);
}
}
QColor DifferencesDrawInterface::getColorForIndex(size_t index) const
{
QColor color;
const size_t resultIndex = index;
if (m_diffResult->isReplaceDifference(resultIndex))
{
color = m_settings->colorReplaced;
}
else if (m_diffResult->isRemoveDifference(resultIndex))
{
color = m_settings->colorRemoved;
}
else if (m_diffResult->isAddDifference(resultIndex))
{
color = m_settings->colorAdded;
}
else if (m_diffResult->isPageMoveDifference(resultIndex))
{
color = m_settings->colorPageMove;
}
return color;
}
void DifferencesDrawInterface::drawPostRendering(QPainter* painter, QRect rect) const
{
Q_UNUSED(painter);
Q_UNUSED(rect);
}
void DifferencesDrawInterface::drawAnnotations(const pdf::PDFDocument* document,
pdf::PDFDocumentBuilder* builder)
{
pdf::PDFInteger pageCount = document->getCatalog()->getPageCount();
QString title = pdf::PDFSysUtils::getUserName();
QString subject = tr("Difference");
for (pdf::PDFInteger pageIndex = 0; pageIndex < pageCount; ++pageIndex)
{
const size_t differencesCount = m_diffResult->getDifferencesCount();
const pdf::PDFInteger leftPageIndex = m_mapper->getLeftPageIndex(pageIndex);
const pdf::PDFInteger rightPageIndex = m_mapper->getRightPageIndex(pageIndex);
const pdf::PDFPage* page = document->getCatalog()->getPage(pageIndex);
pdf::PDFObjectReference reference = page->getPageReference();
if (leftPageIndex != -1)
{
for (size_t i = 0; i < differencesCount; ++i)
{
auto leftRectangles = m_diffResult->getLeftRectangles(i);
for (auto it = leftRectangles.first; it != leftRectangles.second; ++it)
{
const auto& item = *it;
if (item.first == leftPageIndex)
{
QColor color = getColorForIndex(i);
const QRectF& rect = item.second;
QPolygonF polygon;
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft();
pdf::PDFObjectReference annotation = builder->createAnnotationPolygon(reference, polygon, 1.0, color, color, title, subject, m_diffResult->getMessage(i));
builder->setAnnotationOpacity(annotation, 0.3);
builder->updateAnnotationAppearanceStreams(annotation);
}
}
}
}
if (rightPageIndex != -1)
{
for (size_t i = 0; i < differencesCount; ++i)
{
auto rightRectangles = m_diffResult->getRightRectangles(i);
for (auto it = rightRectangles.first; it != rightRectangles.second; ++it)
{
const auto& item = *it;
if (item.first == rightPageIndex)
{
QColor color = getColorForIndex(i);
const QRectF& rect = item.second;
QPolygonF polygon;
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft();
pdf::PDFObjectReference annotation = builder->createAnnotationPolygon(reference, polygon, 1.0, color, color, title, subject, m_diffResult->getMessage(i));
builder->setAnnotationOpacity(annotation, 0.3);
builder->updateAnnotationAppearanceStreams(annotation);
}
}
}
}
}
}
void DifferencesDrawInterface::drawRectangle(QPainter* painter,
const QTransform& pagePointToDevicePointMatrix,
const QRectF& rect,
QColor color) const
{
color.setAlphaF(0.5);
QRectF resultRect = pagePointToDevicePointMatrix.mapRect(rect);
painter->fillRect(resultRect, color);
}
void DifferencesDrawInterface::drawMarker(QPainter* painter,
const QTransform& pagePointToDevicePointMatrix,
const QRectF& rect,
QColor color,
bool isLeft) const
{
if (!m_settings->displayMarkers)
{
return;
}
pdf::PDFPainterStateGuard guard(painter);
QRectF deviceRect = pagePointToDevicePointMatrix.mapRect(rect);
QPointF snapPoint;
QPointF markPoint;
if (isLeft)
{
snapPoint.ry() = deviceRect.center().y();
snapPoint.rx() = deviceRect.left();
markPoint = snapPoint;
markPoint.rx() = 0;
}
else
{
snapPoint.ry() = deviceRect.center().y();
snapPoint.rx() = deviceRect.right();
markPoint = snapPoint;
markPoint.rx() = painter->device()->width();
}
const qreal lineWidthF = pdf::PDFWidgetUtils::scaleDPI_y(painter->device(), 2);
QPen pen(Qt::DotLine);
pen.setColor(color);
pen.setWidthF(lineWidthF);
painter->setBrush(Qt::NoBrush);
painter->setPen(pen);
painter->drawLine(snapPoint, markPoint);
const qreal markSizeX = pdf::PDFWidgetUtils::scaleDPI_x(painter->device(), 10);
const qreal markSizeY = pdf::PDFWidgetUtils::scaleDPI_y(painter->device(), 10);
QPointF ptc = markPoint;
QPointF ptTop = ptc;
QPointF ptBottom = ptc;
ptTop.ry() -= markSizeY;
ptBottom.ry() += markSizeY;
ptc.rx() += isLeft ? markSizeX : -markSizeX;
std::array points = { ptTop, ptc, ptBottom };
painter->setPen(Qt::NoPen);
painter->setBrush(QBrush(color));
painter->drawConvexPolygon(points.data(), int(points.size()));
}
} // namespace pdfdocdiff

View File

@ -1,128 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef UTILS_H
#define UTILS_H
#include "settings.h"
#include "pdfdiff.h"
#include "pdfdrawspacecontroller.h"
#include "pdfdocumentdrawinterface.h"
#include <QtCore>
namespace pdf
{
class PDFDocumentBuilder;
} // namespace pdf
namespace pdfdocdiff
{
class ComparedDocumentMapper
{
public:
enum class Mode
{
Left,
Right,
Combined,
Overlay
};
void update(Mode mode,
bool filterDifferences,
const pdf::PDFDiffResult& diff,
const pdf::PDFDocument* leftDocument,
const pdf::PDFDocument* rightDocument,
const pdf::PDFDocument* currentDocument);
const pdf::PDFDrawSpaceController::LayoutItems& getLayout() const { return m_layout; }
void setPageSequence(const pdf::PDFDiffResult::PageSequence& sequence) { m_pageSequence = sequence; }
/// Returns left page index (that means page index in left document),
/// if it doesn't exist, -1 is returned.
/// \param pageIndex Actual page index
pdf::PDFInteger getLeftPageIndex(pdf::PDFInteger pageIndex) const;
/// Returns right page index (that means page index in right document),
/// if it doesn't exist, -1 is returned.
/// \param pageIndex Actual page index
pdf::PDFInteger getRightPageIndex(pdf::PDFInteger pageIndex) const;
/// Returns actual page index from left page index, or -1.
/// \param leftPageIndex Left page index
pdf::PDFInteger getPageIndexFromLeftPageIndex(pdf::PDFInteger leftPageIndex) const;
/// Returns actual page index from right page index, or -1.
/// \param rightPageIndex Right page index
pdf::PDFInteger getPageIndexFromRightPageIndex(pdf::PDFInteger rightPageIndex) const;
private:
pdf::PDFDrawSpaceController::LayoutItems m_layout;
bool m_allLeft = false;
bool m_allRight = false;
std::map<pdf::PDFInteger, pdf::PDFInteger> m_leftPageIndices;
std::map<pdf::PDFInteger, pdf::PDFInteger> m_rightPageIndices;
pdf::PDFDiffResult::PageSequence m_pageSequence;
};
class DifferencesDrawInterface : public pdf::IDocumentDrawInterface
{
Q_DECLARE_TR_FUNCTIONS(pdfdocdiff::DifferencesDrawInterface)
public:
explicit DifferencesDrawInterface(const Settings* settings,
const ComparedDocumentMapper* mapper,
const pdf::PDFDiffResult* diffResult);
virtual void drawPage(QPainter* painter, pdf::PDFInteger pageIndex,
const pdf::PDFPrecompiledPage* compiledPage,
pdf::PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
QList<pdf::PDFRenderError>& errors) const override;
virtual void drawPostRendering(QPainter* painter, QRect rect) const override;
/// Draw annotations for differences
/// \param document Document
/// \param builder Builder
void drawAnnotations(const pdf::PDFDocument* document, pdf::PDFDocumentBuilder* builder);
private:
void drawRectangle(QPainter* painter,
const QTransform& pagePointToDevicePointMatrix,
const QRectF& rect,
QColor color) const;
void drawMarker(QPainter* painter,
const QTransform& pagePointToDevicePointMatrix,
const QRectF& rect,
QColor color,
bool isLeft) const;
QColor getColorForIndex(size_t index) const;
const Settings* m_settings;
const ComparedDocumentMapper* m_mapper;
const pdf::PDFDiffResult* m_diffResult;
};
} // namespace pdfdocdiff
#endif // UTILS_H

View File

@ -1,41 +0,0 @@
# Copyright (C) 2022 Jakub Melka
#
# This file is part of PDF4QT.
#
# PDF4QT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# with the written consent of the copyright owner, any later version.
#
# PDF4QT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
add_executable(Pdf4QtDocPageOrganizer
aboutdialog.cpp
assembleoutputsettingsdialog.cpp
main.cpp
mainwindow.cpp
pageitemdelegate.cpp
pageitemmodel.cpp
selectbookmarkstoregroupdialog.cpp
aboutdialog.ui
assembleoutputsettingsdialog.ui
mainwindow.ui
selectbookmarkstoregroupdialog.ui
resources.qrc
icon.rc
)
target_link_libraries(Pdf4QtDocPageOrganizer PRIVATE Pdf4QtLib Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(Pdf4QtDocPageOrganizer PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
install(TARGETS Pdf4QtDocPageOrganizer)

View File

@ -1,64 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include "pdfutils.h"
#include "pdfwidgetutils.h"
namespace pdfdocpage
{
PDFAboutDialog::PDFAboutDialog(QWidget* parent) :
QDialog(parent),
ui(new Ui::PDFAboutDialog)
{
ui->setupUi(this);
QString html = ui->copyrightLabel->text();
html.replace("PdfForQtViewer", QString("%1 %2").arg(QApplication::applicationDisplayName(), QApplication::applicationVersion()));
ui->copyrightLabel->setText(html);
std::vector<pdf::PDFDependentLibraryInfo> infos = pdf::PDFDependentLibraryInfo::getLibraryInfo();
ui->tableWidget->setColumnCount(4);
ui->tableWidget->setRowCount(static_cast<int>(infos.size()));
ui->tableWidget->setHorizontalHeaderLabels(QStringList() << tr("Library") << tr("Version") << tr("License") << tr("URL"));
ui->tableWidget->setEditTriggers(QTableWidget::NoEditTriggers);
ui->tableWidget->setSelectionMode(QTableView::SingleSelection);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
for (int i = 0; i < infos.size(); ++i)
{
const pdf::PDFDependentLibraryInfo& info = infos[i];
ui->tableWidget->setItem(i, 0, new QTableWidgetItem(info.library));
ui->tableWidget->setItem(i, 1, new QTableWidgetItem(info.version));
ui->tableWidget->setItem(i, 2, new QTableWidgetItem(info.license));
ui->tableWidget->setItem(i, 3, new QTableWidgetItem(info.url));
}
pdf::PDFWidgetUtils::scaleWidget(this, QSize(750, 600));
pdf::PDFWidgetUtils::style(this);
}
PDFAboutDialog::~PDFAboutDialog()
{
delete ui;
}
} // namespace pdfdocpage

View File

@ -1,45 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDOCPAGEORGANIZER_PDFABOUTDIALOG_H
#define PDFDOCPAGEORGANIZER_PDFABOUTDIALOG_H
#include <QDialog>
namespace Ui
{
class PDFAboutDialog;
}
namespace pdfdocpage
{
class PDFAboutDialog : public QDialog
{
Q_OBJECT
public:
explicit PDFAboutDialog(QWidget* parent);
virtual ~PDFAboutDialog() override;
private:
Ui::PDFAboutDialog* ui;
};
} // namespace pdfdocpage
#endif // PDFDOCPAGEORGANIZER_PDFABOUTDIALOG_H

View File

@ -1,269 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PDFAboutDialog</class>
<widget class="QDialog" name="PDFAboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>600</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>900</width>
<height>600</height>
</size>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="copyrightLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;PdfForQtViewer&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Copyright 2018-2021 Jakub Melka. All rights reserved.&lt;/p&gt;&lt;p&gt;THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEdit">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; GNU LESSER GENERAL PUBLIC LICENSE&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Version 3, 29 June 2007&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Copyright (C) 2007 Free Software Foundation, Inc. &amp;lt;https://fsf.org/&amp;gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Everyone is permitted to copy and distribute verbatim copies&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; of this license document, but changing it is not allowed.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; This version of the GNU Lesser General Public License incorporates&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;the terms and conditions of version 3 of the GNU General Public&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;License, supplemented by the additional permissions listed below.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 0. Additional Definitions.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; As used herein, &amp;quot;this License&amp;quot; refers to version 3 of the GNU Lesser&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;General Public License, and the &amp;quot;GNU GPL&amp;quot; refers to version 3 of the GNU&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;General Public License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; &amp;quot;The Library&amp;quot; refers to a covered work governed by this License,&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;other than an Application or a Combined Work as defined below.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; An &amp;quot;Application&amp;quot; is any work that makes use of an interface provided&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;by the Library, but which is not otherwise based on the Library.&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Defining a subclass of a class defined by the Library is deemed a mode&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;of using an interface provided by the Library.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; A &amp;quot;Combined Work&amp;quot; is a work produced by combining or linking an&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Application with the Library. The particular version of the Library&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;with which the Combined Work was made is also called the &amp;quot;Linked&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Version&amp;quot;.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; The &amp;quot;Minimal Corresponding Source&amp;quot; for a Combined Work means the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Corresponding Source for the Combined Work, excluding any source code&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;for portions of the Combined Work that, considered in isolation, are&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;based on the Application, and not on the Linked Version.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; The &amp;quot;Corresponding Application Code&amp;quot; for a Combined Work means the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;object code and/or source code for the Application, including any data&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;and utility programs needed for reproducing the Combined Work from the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Application, but excluding the System Libraries of the Combined Work.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 1. Exception to Section 3 of the GNU GPL.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; You may convey a covered work under sections 3 and 4 of this License&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;without being bound by section 3 of the GNU GPL.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 2. Conveying Modified Versions.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; If you modify a copy of the Library, and, in your modifications, a&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;facility refers to a function or data to be supplied by an Application&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;that uses the facility (other than as an argument passed when the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;facility is invoked), then you may convey a copy of the modified&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;version:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a) under this License, provided that you make a good faith effort to&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; ensure that, in the event an Application does not supply the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; function or data, the facility still operates, and performs&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; whatever part of its purpose remains meaningful, or&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; b) under the GNU GPL, with none of the additional permissions of&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; this License applicable to that copy.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 3. Object Code Incorporating Material from Library Header Files.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; The object code form of an Application may incorporate material from&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;a header file that is part of the Library. You may convey such object&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;code under terms of your choice, provided that, if the incorporated&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;material is not limited to numerical parameters, data structure&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;layouts and accessors, or small macros, inline functions and templates&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;(ten or fewer lines in length), you do both of the following:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a) Give prominent notice with each copy of the object code that the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Library is used in it and that the Library and its use are&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; covered by this License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; b) Accompany the object code with a copy of the GNU GPL and this license&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; document.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 4. Combined Works.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; You may convey a Combined Work under terms of your choice that,&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;taken together, effectively do not restrict modification of the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;portions of the Library contained in the Combined Work and reverse&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;engineering for debugging such modifications, if you also do each of&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;the following:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a) Give prominent notice with each copy of the Combined Work that&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; the Library is used in it and that the Library and its use are&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; covered by this License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; b) Accompany the Combined Work with a copy of the GNU GPL and this license&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; document.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; c) For a Combined Work that displays copyright notices during&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; execution, include the copyright notice for the Library among&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; these notices, as well as a reference directing the user to the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; copies of the GNU GPL and this license document.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; d) Do one of the following:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 0) Convey the Minimal Corresponding Source under the terms of this&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; License, and the Corresponding Application Code in a form&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; suitable for, and under terms that permit, the user to&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; recombine or relink the Application with a modified version of&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; the Linked Version to produce a modified Combined Work, in the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; manner specified by section 6 of the GNU GPL for conveying&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Corresponding Source.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 1) Use a suitable shared library mechanism for linking with the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Library. A suitable mechanism is one that (a) uses at run time&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a copy of the Library already present on the user's computer&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; system, and (b) will operate properly with a modified version&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; of the Library that is interface-compatible with the Linked&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Version.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; e) Provide Installation Information, but only if you would otherwise&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; be required to provide such information under section 6 of the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; GNU GPL, and only to the extent that such information is&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; necessary to install and execute a modified version of the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Combined Work produced by recombining or relinking the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Application with a modified version of the Linked Version. (If&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; you use option 4d0, the Installation Information must accompany&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; the Minimal Corresponding Source and Corresponding Application&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Code. If you use option 4d1, you must provide the Installation&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Information in the manner specified by section 6 of the GNU GPL&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; for conveying Corresponding Source.)&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 5. Combined Libraries.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; You may place library facilities that are a work based on the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Library side by side in a single library together with other library&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;facilities that are not Applications and are not covered by this&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;License, and convey such a combined library under terms of your&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;choice, if you do both of the following:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; a) Accompany the combined library with a copy of the same work based&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; on the Library, uncombined with any other library facilities,&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; conveyed under the terms of this License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; b) Give prominent notice with the combined library that part of it&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; is a work based on the Library, and explaining where to find the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; accompanying uncombined form of the same work.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; 6. Revised Versions of the GNU Lesser General Public License.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; The Free Software Foundation may publish revised and/or new versions&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;of the GNU Lesser General Public License from time to time. Such new&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;versions will be similar in spirit to the present version, but may&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;differ in detail to address new problems or concerns.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; Each version is given a distinguishing version number. If the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Library as you received it specifies that a certain numbered version&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;of the GNU Lesser General Public License &amp;quot;or any later version&amp;quot;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;applies to it, you have the option of following the terms and&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;conditions either of that published version or of any later version&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;published by the Free Software Foundation. If the Library as you&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;received it does not specify a version number of the GNU Lesser&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;General Public License, you may choose any version of the GNU Lesser&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;General Public License ever published by the Free Software Foundation.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; If the Library as you received it specifies that a proxy can decide&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;whether future versions of the GNU Lesser General Public License shall&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;apply, that proxy's public statement of acceptance of any version is&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;permanent authorization for you to choose that version for the&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Library.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="usedLibrariesLabel">
<property name="text">
<string>Used libraries</string>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="tableWidget"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PDFAboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PDFAboutDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,78 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "assembleoutputsettingsdialog.h"
#include "ui_assembleoutputsettingsdialog.h"
#include "pdfwidgetutils.h"
#include <QFileDialog>
namespace pdfdocpage
{
AssembleOutputSettingsDialog::AssembleOutputSettingsDialog(QString directory, QWidget* parent) :
QDialog(parent),
ui(new Ui::AssembleOutputSettingsDialog)
{
ui->setupUi(this);
ui->directoryEdit->setText(directory);
ui->outlineModeComboBox->addItem(tr("No Outline"), int(pdf::PDFDocumentManipulator::OutlineMode::NoOutline));
ui->outlineModeComboBox->addItem(tr("Join Outlines"), int(pdf::PDFDocumentManipulator::OutlineMode::Join));
ui->outlineModeComboBox->addItem(tr("Document Parts"), int(pdf::PDFDocumentManipulator::OutlineMode::DocumentParts));
ui->outlineModeComboBox->setCurrentIndex(ui->outlineModeComboBox->findData(int(pdf::PDFDocumentManipulator::OutlineMode::DocumentParts)));
pdf::PDFWidgetUtils::scaleWidget(this, QSize(450, 150));
pdf::PDFWidgetUtils::style(this);
}
AssembleOutputSettingsDialog::~AssembleOutputSettingsDialog()
{
delete ui;
}
QString AssembleOutputSettingsDialog::getDirectory() const
{
return ui->directoryEdit->text();
}
QString AssembleOutputSettingsDialog::getFileName() const
{
return ui->fileTemplateEdit->text();
}
bool AssembleOutputSettingsDialog::isOverwriteFiles() const
{
return ui->overwriteFilesCheckBox->isChecked();
}
pdf::PDFDocumentManipulator::OutlineMode AssembleOutputSettingsDialog::getOutlineMode() const
{
return pdf::PDFDocumentManipulator::OutlineMode(ui->outlineModeComboBox->currentData().toInt());
}
void AssembleOutputSettingsDialog::on_selectDirectoryButton_clicked()
{
QString directory = QFileDialog::getExistingDirectory(this, tr("Select output directory"), ui->directoryEdit->text());
if (!directory.isEmpty())
{
ui->directoryEdit->setText(directory);
}
}
} // namespace pdfdocpage

View File

@ -1,55 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDOCPAGEORGANIZER_ASSEMBLEOUTPUTSETTINGSDIALOG_H
#define PDFDOCPAGEORGANIZER_ASSEMBLEOUTPUTSETTINGSDIALOG_H
#include "pdfdocumentmanipulator.h"
#include <QDialog>
namespace Ui
{
class AssembleOutputSettingsDialog;
}
namespace pdfdocpage
{
class AssembleOutputSettingsDialog : public QDialog
{
Q_OBJECT
public:
explicit AssembleOutputSettingsDialog(QString directory, QWidget* parent);
virtual ~AssembleOutputSettingsDialog() override;
QString getDirectory() const;
QString getFileName() const;
bool isOverwriteFiles() const;
pdf::PDFDocumentManipulator::OutlineMode getOutlineMode() const;
private slots:
void on_selectDirectoryButton_clicked();
private:
Ui::AssembleOutputSettingsDialog* ui;
};
} // namespace pdfdocpage
#endif // PDFDOCPAGEORGANIZER_ASSEMBLEOUTPUTSETTINGSDIALOG_H

View File

@ -1,50 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdfconstants.h"
#include "mainwindow.h"
#include <QApplication>
#include <QCommandLineParser>
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
#if !defined(Q_OS_WIN)
QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, true);
#endif
QApplication application(argc, argv);
QCoreApplication::setOrganizationName("MelkaJ");
QCoreApplication::setApplicationName("PDF4QT DocPage Organizer");
QCoreApplication::setApplicationVersion(pdf::PDF_LIBRARY_VERSION);
QApplication::setApplicationDisplayName(QApplication::translate("Application", "PDF4QT DocPage Organizer"));
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::applicationName());
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("file", "The PDF file to open.");
parser.process(application);
pdfdocpage::MainWindow mainWindow(nullptr);
mainWindow.show();
return application.exec();
}

View File

@ -1,955 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "aboutdialog.h"
#include "assembleoutputsettingsdialog.h"
#include "selectbookmarkstoregroupdialog.h"
#include "pdfaction.h"
#include "pdfwidgetutils.h"
#include "pdfdocumentreader.h"
#include "pdfdocumentwriter.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
#include <QClipboard>
#include <QToolBar>
#include <QDesktopServices>
#include <QImageReader>
#include <QPixmapCache>
#include <QScreen>
#include <QGuiApplication>
namespace pdfdocpage
{
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_model(new PageItemModel(this)),
m_delegate(new PageItemDelegate(m_model, this)),
m_dropAction(Qt::IgnoreAction)
{
ui->setupUi(this);
m_delegate->setPageImageSize(getDefaultPageImageSize());
ui->documentItemsView->setModel(m_model);
ui->documentItemsView->setItemDelegate(m_delegate);
setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600)));
ui->actionClear->setData(int(Operation::Clear));
ui->actionCloneSelection->setData(int(Operation::CloneSelection));
ui->actionRemoveSelection->setData(int(Operation::RemoveSelection));
ui->actionReplaceSelection->setData(int(Operation::ReplaceSelection));
ui->actionRestoreRemovedItems->setData(int(Operation::RestoreRemovedItems));
ui->actionUndo->setData(int(Operation::Undo));
ui->actionRedo->setData(int(Operation::Redo));
ui->actionCut->setData(int(Operation::Cut));
ui->actionCopy->setData(int(Operation::Copy));
ui->actionPaste->setData(int(Operation::Paste));
ui->actionRotate_Left->setData(int(Operation::RotateLeft));
ui->actionRotate_Right->setData(int(Operation::RotateRight));
ui->actionGroup->setData(int(Operation::Group));
ui->actionUngroup->setData(int(Operation::Ungroup));
ui->actionSelect_None->setData(int(Operation::SelectNone));
ui->actionSelect_All->setData(int(Operation::SelectAll));
ui->actionSelect_Even->setData(int(Operation::SelectEven));
ui->actionSelect_Odd->setData(int(Operation::SelectOdd));
ui->actionSelect_Portrait->setData(int(Operation::SelectPortrait));
ui->actionSelect_Landscape->setData(int(Operation::SelectLandscape));
ui->actionZoom_In->setData(int(Operation::ZoomIn));
ui->actionZoom_Out->setData(int(Operation::ZoomOut));
ui->actionUnited_Document->setData(int(Operation::Unite));
ui->actionSeparate_to_Multiple_Documents->setData(int(Operation::Separate));
ui->actionSeparate_to_Multiple_Documents_Grouped->setData(int(Operation::SeparateGrouped));
ui->actionInsert_Image->setData(int(Operation::InsertImage));
ui->actionInsert_Empty_Page->setData(int(Operation::InsertEmptyPage));
ui->actionInsert_PDF->setData(int(Operation::InsertPDF));
ui->actionGet_Source->setData(int(Operation::GetSource));
ui->actionAbout->setData(int(Operation::About));
ui->actionInvert_Selection->setData(int(Operation::InvertSelection));
ui->actionRegroup_Even_Odd->setData(int(Operation::RegroupEvenOdd));
ui->actionRegroup_by_Page_Pairs->setData(int(Operation::RegroupPaired));
ui->actionRegroup_by_Bookmarks->setData(int(Operation::RegroupBookmarks));
ui->actionRegroup_by_Alternating_Pages->setData(int(Operation::RegroupAlternatingPages));
ui->actionRegroup_by_Alternating_Pages_Reversed_Order->setData(int(Operation::RegroupAlternatingPagesReversed));
ui->actionPrepare_Icon_Theme->setData(int(Operation::PrepareIconTheme));
m_iconTheme.registerAction(ui->actionAddDocuments, ":/pdfdocpage/resources/open.svg");
m_iconTheme.registerAction(ui->actionClose, ":/pdfdocpage/resources/close.svg");
m_iconTheme.registerAction(ui->actionCloneSelection, ":/pdfdocpage/resources/clone-selection.svg");
m_iconTheme.registerAction(ui->actionRemoveSelection, ":/pdfdocpage/resources/remove-selection.svg");
m_iconTheme.registerAction(ui->actionRestoreRemovedItems, ":/pdfdocpage/resources/restore-removed-items.svg");
m_iconTheme.registerAction(ui->actionInsert_PDF, ":/pdfdocpage/resources/insert-page-from-pdf.svg");
m_iconTheme.registerAction(ui->actionInsert_Image, ":/pdfdocpage/resources/insert-image.svg");
m_iconTheme.registerAction(ui->actionInsert_Empty_Page, ":/pdfdocpage/resources/insert-empty-page.svg");
m_iconTheme.registerAction(ui->actionCut, ":/pdfdocpage/resources/cut.svg");
m_iconTheme.registerAction(ui->actionCopy, ":/pdfdocpage/resources/copy.svg");
m_iconTheme.registerAction(ui->actionPaste, ":/pdfdocpage/resources/paste.svg");
m_iconTheme.registerAction(ui->actionReplaceSelection, ":/pdfdocpage/resources/replace-selection.svg");
m_iconTheme.registerAction(ui->actionSelect_None, ":/pdfdocpage/resources/select-none.svg");
m_iconTheme.registerAction(ui->actionSelect_All, ":/pdfdocpage/resources/select-all.svg");
m_iconTheme.registerAction(ui->actionSelect_Even, ":/pdfdocpage/resources/select-even.svg");
m_iconTheme.registerAction(ui->actionSelect_Odd, ":/pdfdocpage/resources/select-odd.svg");
m_iconTheme.registerAction(ui->actionSelect_Portrait, ":/pdfdocpage/resources/select-portrait.svg");
m_iconTheme.registerAction(ui->actionSelect_Landscape, ":/pdfdocpage/resources/select-landscape.svg");
m_iconTheme.registerAction(ui->actionRotate_Right, ":/pdfdocpage/resources/rotate-right.svg");
m_iconTheme.registerAction(ui->actionRotate_Left, ":/pdfdocpage/resources/rotate-left.svg");
m_iconTheme.registerAction(ui->actionZoom_In, ":/pdfdocpage/resources/zoom-in.svg");
m_iconTheme.registerAction(ui->actionZoom_Out, ":/pdfdocpage/resources/zoom-out.svg");
m_iconTheme.registerAction(ui->actionGet_Source, ":/pdfdocpage/resources/get-source.svg");
m_iconTheme.registerAction(ui->actionAbout, ":/pdfdocpage/resources/about.svg");
m_iconTheme.registerAction(ui->actionUnited_Document, ":/pdfdocpage/resources/make-united-document.svg");
m_iconTheme.registerAction(ui->actionSeparate_to_Multiple_Documents, ":/pdfdocpage/resources/make-separated-document.svg");
m_iconTheme.registerAction(ui->actionSeparate_to_Multiple_Documents_Grouped, ":/pdfdocpage/resources/make-separated-document-from-groups.svg");
m_iconTheme.registerAction(ui->actionGroup, ":/pdfdocpage/resources/group.svg");
m_iconTheme.registerAction(ui->actionUngroup, ":/pdfdocpage/resources/ungroup.svg");
m_iconTheme.registerAction(ui->actionClear, ":/pdfdocpage/resources/clear.svg");
m_iconTheme.registerAction(ui->actionRegroup_Even_Odd, ":/pdfdocpage/resources/regroup-even-odd.svg");
m_iconTheme.registerAction(ui->actionRegroup_by_Page_Pairs, ":/pdfdocpage/resources/regroup-pairs.svg");
m_iconTheme.registerAction(ui->actionRegroup_by_Bookmarks, ":/pdfdocpage/resources/regroup-bookmarks.svg");
m_iconTheme.registerAction(ui->actionRegroup_by_Alternating_Pages, ":/pdfdocpage/resources/regroup-alternating.svg");
m_iconTheme.registerAction(ui->actionRegroup_by_Alternating_Pages_Reversed_Order, ":/pdfdocpage/resources/regroup-alternating-reversed.svg");
m_iconTheme.registerAction(ui->actionInvert_Selection, ":/pdfdocpage/resources/invert-selection.svg");
m_iconTheme.registerAction(ui->actionUndo, ":/pdfdocpage/resources/undo.svg");
m_iconTheme.registerAction(ui->actionRedo, ":/pdfdocpage/resources/redo.svg");
m_iconTheme.setDirectory("pdfdocpage_theme");
m_iconTheme.setPrefix(":/pdfdocpage/resources/");
m_iconTheme.loadTheme();
QToolBar* mainToolbar = addToolBar(tr("Main"));
mainToolbar->setObjectName("main_toolbar");
mainToolbar->addAction(ui->actionAddDocuments);
mainToolbar->addSeparator();
mainToolbar->addActions({ ui->actionCloneSelection, ui->actionRemoveSelection });
mainToolbar->addSeparator();
mainToolbar->addActions({ ui->actionUndo, ui->actionRedo });
mainToolbar->addSeparator();
mainToolbar->addActions({ ui->actionCut, ui->actionCopy, ui->actionPaste });
mainToolbar->addSeparator();
mainToolbar->addActions({ ui->actionGroup, ui->actionUngroup });
QToolBar* insertToolbar = addToolBar(tr("Insert"));
insertToolbar->setObjectName("insert_toolbar");
insertToolbar->addActions({ ui->actionInsert_PDF, ui->actionInsert_Image, ui->actionInsert_Empty_Page });
QToolBar* selectToolbar = addToolBar(tr("Select"));
selectToolbar->setObjectName("select_toolbar");
selectToolbar->addActions({ ui->actionSelect_None, ui->actionSelect_All, ui->actionSelect_Even, ui->actionSelect_Odd, ui->actionSelect_Portrait, ui->actionSelect_Landscape, ui->actionInvert_Selection });
QToolBar* regroupToolbar = addToolBar(tr("Regroup"));
regroupToolbar->setObjectName("regroup_toolbar");
regroupToolbar->addActions({ ui->actionRegroup_Even_Odd, ui->actionRegroup_by_Page_Pairs, ui->actionRegroup_by_Bookmarks, ui->actionRegroup_by_Alternating_Pages, ui->actionRegroup_by_Alternating_Pages_Reversed_Order });
QToolBar* zoomToolbar = addToolBar(tr("Zoom"));
zoomToolbar->setObjectName("zoom_toolbar");
zoomToolbar->addActions({ ui->actionZoom_In, ui->actionZoom_Out });
QToolBar* makeToolbar = addToolBar(tr("Make"));
makeToolbar->setObjectName("make_toolbar");
makeToolbar->addActions({ ui->actionUnited_Document, ui->actionSeparate_to_Multiple_Documents, ui->actionSeparate_to_Multiple_Documents_Grouped });
QSize iconSize = pdf::PDFWidgetUtils::scaleDPI(this, QSize(24, 24));
auto toolbars = findChildren<QToolBar*>();
for (QToolBar* toolbar : toolbars)
{
toolbar->setIconSize(iconSize);
ui->menuToolbars->addAction(toolbar->toggleViewAction());
}
connect(&m_mapper, &QSignalMapper::mappedInt, this, &MainWindow::onMappedActionTriggered);
connect(ui->documentItemsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::updateActions);
QList<QAction*> actions = findChildren<QAction*>();
for (QAction* action : actions)
{
QVariant actionData = action->data();
if (actionData.isValid())
{
connect(action, &QAction::triggered, &m_mapper, QOverload<>::of(&QSignalMapper::map));
m_mapper.setMapping(action, actionData.toInt());
}
}
// Initialize pixmap cache size
const int depth = 4; // 4 bytes (ARGB)
const int reserveSize = 2; // Caching of two screens
QSize size = QGuiApplication::primaryScreen()->availableVirtualSize();
int bytes = size.width() * size.height() * depth * reserveSize;
int kBytes = bytes / 1024;
QPixmapCache::setCacheLimit(kBytes);
loadSettings();
updateActions();
}
MainWindow::~MainWindow()
{
saveSettings();
delete ui;
}
QSize MainWindow::getMinPageImageSize() const
{
return pdf::PDFWidgetUtils::scaleDPI(this, QSize(40, 40));
}
QSize MainWindow::getDefaultPageImageSize() const
{
return pdf::PDFWidgetUtils::scaleDPI(this, QSize(100, 100));
}
QSize MainWindow::getMaxPageImageSize() const
{
return pdf::PDFWidgetUtils::scaleDPI(this, QSize(250, 250));
}
void MainWindow::on_actionClose_triggered()
{
close();
}
void MainWindow::on_actionAddDocuments_triggered()
{
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select PDF document(s)"), m_settings.directory, tr("PDF document (*.pdf)"));
if (!fileNames.isEmpty())
{
for (const QString& fileName : fileNames)
{
if (!insertDocument(fileName, QModelIndex()))
{
break;
}
}
}
}
void MainWindow::onMappedActionTriggered(int actionId)
{
performOperation(static_cast<Operation>(actionId));
}
void MainWindow::updateActions()
{
QList<QAction*> actions = findChildren<QAction*>();
for (QAction* action : actions)
{
QVariant actionData = action->data();
if (actionData.isValid())
{
action->setEnabled(canPerformOperation(static_cast<Operation>(actionData.toInt())));
}
}
}
void MainWindow::loadSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.beginGroup("MainWindow");
QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
if (geometry.isEmpty())
{
QRect availableGeometry = QApplication::primaryScreen()->availableGeometry();
QRect windowRect(0, 0, availableGeometry.width() / 2, availableGeometry.height() / 2);
windowRect = windowRect.translated(availableGeometry.center() - windowRect.center());
setGeometry(windowRect);
}
else
{
restoreGeometry(geometry);
}
QByteArray state = settings.value("windowState", QByteArray()).toByteArray();
if (!state.isEmpty())
{
restoreState(state);
}
settings.endGroup();
settings.beginGroup("Settings");
m_settings.directory = settings.value("directory").toString();
settings.endGroup();
}
void MainWindow::saveSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.beginGroup("MainWindow");
settings.setValue("geometry", saveGeometry());
settings.setValue("windowState", saveState());
settings.endGroup();
settings.beginGroup("Settings");
settings.setValue("directory", m_settings.directory);
settings.endGroup();
}
bool MainWindow::insertDocument(const QString& fileName, const QModelIndex& insertIndex)
{
bool isDocumentInserted = true;
QFileInfo fileInfo(fileName);
auto queryPassword = [this, &fileInfo](bool* ok)
{
*ok = false;
return QInputDialog::getText(this, tr("Encrypted document"), tr("Enter password to access document '%1'").arg(fileInfo.fileName()), QLineEdit::Password, QString(), ok);
};
// Mark current directory as this
m_settings.directory = fileInfo.dir().absolutePath();
// Try to open a new document
pdf::PDFDocumentReader reader(nullptr, qMove(queryPassword), true, false);
pdf::PDFDocument document = reader.readFromFile(fileName);
QString errorMessage = reader.getErrorMessage();
pdf::PDFDocumentReader::Result result = reader.getReadingResult();
if (result == pdf::PDFDocumentReader::Result::OK)
{
const pdf::PDFSecurityHandler* securityHandler = document.getStorage().getSecurityHandler();
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::Assemble) ||
securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::Modify))
{
m_model->insertDocument(fileName, qMove(document), insertIndex);
}
else
{
isDocumentInserted = false;
QMessageBox::critical(this, tr("Error"), tr("Document security doesn't permit to organize pages."));
}
}
else if (result == pdf::PDFDocumentReader::Result::Failed)
{
isDocumentInserted = false;
QMessageBox::critical(this, tr("Error"), errorMessage);
}
else if (result == pdf::PDFDocumentReader::Result::Cancelled)
{
isDocumentInserted = false;
}
updateActions();
return isDocumentInserted;
}
bool MainWindow::canPerformOperation(Operation operation) const
{
QModelIndexList selection = ui->documentItemsView->selectionModel()->selection().indexes();
const bool isSelected = !selection.isEmpty();
const bool isMultiSelected = selection.size() > 1;
const bool isModelEmpty = m_model->rowCount(QModelIndex()) == 0;
switch (operation)
{
case Operation::Clear:
return true;
case Operation::CloneSelection:
case Operation::RemoveSelection:
case Operation::ReplaceSelection:
return isSelected;
case Operation::RestoreRemovedItems:
return !m_model->isTrashBinEmpty();
case Operation::Undo:
return m_model->canUndo();
case Operation::Redo:
return m_model->canRedo();
case Operation::Cut:
case Operation::Copy:
return isSelected;
case Operation::Paste:
{
const QMimeData* mimeData = QApplication::clipboard()->mimeData();
return mimeData && mimeData->hasFormat(PageItemModel::getMimeDataType());
}
case Operation::RotateLeft:
case Operation::RotateRight:
return isSelected;
case Operation::Group:
return isMultiSelected;
case Operation::Ungroup:
return m_model->isGrouped(selection);
case Operation::SelectNone:
return isSelected;
case Operation::SelectAll:
case Operation::SelectEven:
case Operation::SelectOdd:
case Operation::SelectPortrait:
case Operation::SelectLandscape:
return !isModelEmpty;
case Operation::ZoomIn:
return m_delegate->getPageImageSize() != getMaxPageImageSize();
case Operation::ZoomOut:
return m_delegate->getPageImageSize() != getMinPageImageSize();
case Operation::Unite:
case Operation::Separate:
case Operation::SeparateGrouped:
return !isModelEmpty;
case Operation::InsertImage:
case Operation::InsertEmptyPage:
case Operation::InsertPDF:
case Operation::GetSource:
case Operation::About:
case Operation::PrepareIconTheme:
return true;
case Operation::InvertSelection:
return !isModelEmpty;
case Operation::RegroupEvenOdd:
{
PageItemModel::SelectionInfo info = m_model->getSelectionInfo(selection);
return info.isDocumentOnly();
}
case Operation::RegroupPaired:
return !isModelEmpty && !selection.isEmpty();
case Operation::RegroupBookmarks:
{
PageItemModel::SelectionInfo info = m_model->getSelectionInfo(selection);
return info.isSingleDocument();
}
case Operation::RegroupAlternatingPages:
case Operation::RegroupAlternatingPagesReversed:
{
PageItemModel::SelectionInfo info = m_model->getSelectionInfo(selection);
return info.isTwoDocuments();
}
default:
Q_ASSERT(false);
break;
}
return false;
}
void MainWindow::performOperation(Operation operation)
{
switch (operation)
{
case Operation::Clear:
{
m_model->clear();
QPixmapCache::clear();
break;
}
case Operation::CloneSelection:
{
m_model->cloneSelection(ui->documentItemsView->selectionModel()->selection().indexes());
break;
}
case Operation::RemoveSelection:
{
m_model->removeSelection(ui->documentItemsView->selectionModel()->selection().indexes());
break;
}
case Operation::RestoreRemovedItems:
{
QModelIndexList restoredItemIndices = m_model->restoreRemovedItems();
QItemSelection itemSelection;
for (const QModelIndex& index : restoredItemIndices)
{
itemSelection.select(index, index);
}
ui->documentItemsView->selectionModel()->select(itemSelection, QItemSelectionModel::ClearAndSelect);
break;
}
case Operation::Undo:
{
m_model->undo();
break;
}
case Operation::Redo:
{
m_model->redo();
break;
}
case Operation::Cut:
case Operation::Copy:
{
QModelIndexList indices = ui->documentItemsView->selectionModel()->selection().indexes();
if (indices.isEmpty())
{
return;
}
if (QMimeData* mimeData = m_model->mimeData(indices))
{
QApplication::clipboard()->setMimeData(mimeData);
}
ui->documentItemsView->clearSelection();
m_dropAction = (operation == Operation::Cut) ? Qt::MoveAction : Qt::CopyAction;
break;
}
case Operation::Paste:
{
QModelIndexList indices = ui->documentItemsView->selectionModel()->selection().indexes();
int insertRow = m_model->rowCount(QModelIndex()) - 1;
if (!indices.isEmpty())
{
insertRow = indices.back().row();
}
QModelIndex insertIndex = m_model->index(insertRow, 0, QModelIndex());
const QMimeData* mimeData = QApplication::clipboard()->mimeData();
if (m_model->canDropMimeData(mimeData, m_dropAction, -1, -1, insertIndex))
{
m_model->dropMimeData(mimeData, m_dropAction, -1, -1, insertIndex);
}
break;
}
case Operation::Group:
m_model->group(ui->documentItemsView->selectionModel()->selection().indexes());
break;
case Operation::Ungroup:
m_model->ungroup(ui->documentItemsView->selectionModel()->selection().indexes());
break;
case Operation::SelectNone:
ui->documentItemsView->clearSelection();
break;
case Operation::SelectAll:
ui->documentItemsView->selectAll();
break;
case Operation::SelectEven:
ui->documentItemsView->selectionModel()->select(m_model->getSelectionEven(), QItemSelectionModel::ClearAndSelect);
break;
case Operation::SelectOdd:
ui->documentItemsView->selectionModel()->select(m_model->getSelectionOdd(), QItemSelectionModel::ClearAndSelect);
break;
case Operation::SelectPortrait:
ui->documentItemsView->selectionModel()->select(m_model->getSelectionPortrait(), QItemSelectionModel::ClearAndSelect);
break;
case Operation::SelectLandscape:
ui->documentItemsView->selectionModel()->select(m_model->getSelectionLandscape(), QItemSelectionModel::ClearAndSelect);
break;
case Operation::ZoomIn:
{
QSize pageImageSize = m_delegate->getPageImageSize();
pageImageSize *= 1.2;
pageImageSize = pageImageSize.boundedTo(getMaxPageImageSize());
if (pageImageSize != m_delegate->getPageImageSize())
{
m_delegate->setPageImageSize(pageImageSize);
}
break;
}
case Operation::ZoomOut:
{
QSize pageImageSize = m_delegate->getPageImageSize();
pageImageSize /= 1.2;
pageImageSize = pageImageSize.expandedTo(getMinPageImageSize());
if (pageImageSize != m_delegate->getPageImageSize())
{
m_delegate->setPageImageSize(pageImageSize);
}
break;
}
case Operation::RotateLeft:
m_model->rotateLeft(ui->documentItemsView->selectionModel()->selection().indexes());
break;
case Operation::RotateRight:
m_model->rotateRight(ui->documentItemsView->selectionModel()->selection().indexes());
break;
case Operation::GetSource:
QDesktopServices::openUrl(QUrl("https://github.com/JakubMelka/PDF4QT"));
break;
case Operation::InsertEmptyPage:
m_model->insertEmptyPage(ui->documentItemsView->selectionModel()->selection().indexes());
break;
case Operation::About:
{
PDFAboutDialog aboutDialog(this);
aboutDialog.exec();
break;
}
case Operation::PrepareIconTheme:
m_iconTheme.prepareTheme();
break;
case Operation::Unite:
case Operation::Separate:
case Operation::SeparateGrouped:
{
PageItemModel::AssembleMode assembleMode = PageItemModel::AssembleMode::Unite;
switch (operation)
{
case Operation::Unite:
assembleMode = PageItemModel::AssembleMode::Unite;
break;
case Operation::Separate:
assembleMode = PageItemModel::AssembleMode::Separate;
break;
case Operation::SeparateGrouped:
assembleMode = PageItemModel::AssembleMode::SeparateGrouped;
break;
default:
Q_ASSERT(false);
}
std::vector<std::vector<pdf::PDFDocumentManipulator::AssembledPage>> assembledDocuments = m_model->getAssembledPages(assembleMode);
// Check we have something to process
if (assembledDocuments.empty())
{
QMessageBox::critical(this, tr("Error"), tr("No documents to assemble."));
break;
}
AssembleOutputSettingsDialog dialog(m_settings.directory, this);
if (dialog.exec() == QDialog::Accepted)
{
pdf::PDFDocumentManipulator manipulator;
// Add documents and images
for (const auto& documentItem : m_model->getDocuments())
{
manipulator.addDocument(documentItem.first, &documentItem.second.document);
}
for (const auto& imageItem : m_model->getImages())
{
manipulator.addImage(imageItem.first, imageItem.second.image);
}
// Jakub Melka: create assembled documents
pdf::PDFOperationResult result(true);
std::vector<std::pair<QString, pdf::PDFDocument>> assembledDocumentStorage;
int sourceDocumentIndex = 1;
int assembledDocumentIndex = 1;
int sourcePageIndex = 1;
int documentCount = int(m_model->getDocuments().size());
QString directory = dialog.getDirectory();
QString fileNameTemplate = dialog.getFileName();
const bool isOverwriteEnabled = dialog.isOverwriteFiles();
pdf::PDFDocumentManipulator::OutlineMode outlineMode = dialog.getOutlineMode();
manipulator.setOutlineMode(outlineMode);
if (!directory.endsWith('/'))
{
directory += "/";
}
auto replaceInString = [](QString& templateString, QChar character, int number)
{
int index = templateString.indexOf(character, 0, Qt::CaseSensitive);
if (index != -1)
{
int lastIndex = templateString.lastIndexOf(character, -1, Qt::CaseSensitive);
int count = lastIndex - index + 1;
QString textNumber = QString::number(number);
textNumber = textNumber.rightJustified(count, '0', false);
templateString.remove(index, count);
templateString.insert(index, textNumber);
}
};
for (const std::vector<pdf::PDFDocumentManipulator::AssembledPage>& assembledPages : assembledDocuments)
{
pdf::PDFOperationResult currentResult = manipulator.assemble(assembledPages);
if (!currentResult && result)
{
result = currentResult;
break;
}
pdf::PDFDocumentManipulator::AssembledPage samplePage = assembledPages.front();
sourceDocumentIndex = samplePage.documentIndex == -1 ? documentCount + samplePage.imageIndex : samplePage.documentIndex;
sourcePageIndex = qMax(int(samplePage.pageIndex + 1), 1);
QString fileName = fileNameTemplate;
replaceInString(fileName, '#', assembledDocumentIndex);
replaceInString(fileName, '@', sourcePageIndex);
replaceInString(fileName, '%', sourceDocumentIndex);
if (!fileName.endsWith(".pdf"))
{
fileName += ".pdf";
}
fileName.prepend(directory);
assembledDocumentStorage.emplace_back(std::make_pair(std::move(fileName), manipulator.takeAssembledDocument()));
++assembledDocumentIndex;
}
if (!result)
{
QMessageBox::critical(this, tr("Error"), result.getErrorMessage());
return;
}
// Now, try to save files
for (const auto& assembledDocumentItem : assembledDocumentStorage)
{
QString filename = assembledDocumentItem.first;
const pdf::PDFDocument* document = &assembledDocumentItem.second;
const bool isDocumentFileAlreadyExisting = QFile::exists(filename);
if (!isOverwriteEnabled && isDocumentFileAlreadyExisting)
{
QMessageBox::critical(this, tr("Error"), tr("Document with given filename already exists."));
return;
}
pdf::PDFDocumentWriter writer(nullptr);
pdf::PDFOperationResult writeResult = writer.write(filename, document, isDocumentFileAlreadyExisting);
if (!writeResult)
{
QMessageBox::critical(this, tr("Error"), writeResult.getErrorMessage());
return;
}
}
}
break;
}
case Operation::InsertImage:
{
QStringList filters;
for (const QByteArray& imageFormat : QImageReader::supportedImageFormats())
{
filters << QString::fromLatin1(imageFormat).toLower();
}
QString filter = tr("Images (*.%1)").arg(filters.join(" *."));
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Image(s)"), m_settings.directory, filter, nullptr);
if (!fileNames.isEmpty())
{
QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
QModelIndex insertIndex = !indexes.isEmpty() ? indexes.front() : QModelIndex();
for (const QString& fileName : fileNames)
{
m_model->insertImage(fileName, insertIndex);
insertIndex = insertIndex.sibling(insertIndex.row() + 1, insertIndex.column());
}
}
break;
}
case Operation::InsertPDF:
{
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select PDF document(s)"), m_settings.directory, tr("PDF document (*.pdf)"));
if (!fileNames.isEmpty())
{
QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
QModelIndex insertIndex = !indexes.isEmpty() ? indexes.front() : QModelIndex();
for (const QString& fileName : fileNames)
{
if (!insertDocument(fileName, insertIndex))
{
break;
}
insertIndex = insertIndex.sibling(insertIndex.row() + 1, insertIndex.column());
}
}
break;
}
case Operation::ReplaceSelection:
{
QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
if (indexes.isEmpty())
{
// Jakub Melka: we have nothing to do, selection is empty
return;
}
QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)"));
if (!fileName.isEmpty())
{
insertDocument(fileName, indexes.back());
m_model->removeSelection(indexes);
}
break;
}
case Operation::InvertSelection:
{
QModelIndex rootIndex = ui->documentItemsView->rootIndex();
if (rootIndex.isValid())
{
QModelIndex firstIndex = rootIndex.model()->index(0, 0, rootIndex);
QModelIndex lastIndex = rootIndex.model()->index(rootIndex.model()->rowCount() - 1, 0, rootIndex);
QItemSelection selection(firstIndex, lastIndex);
ui->documentItemsView->selectionModel()->select(selection, QItemSelectionModel::Toggle);
}
break;
}
case Operation::RegroupEvenOdd:
{
QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
m_model->regroupEvenOdd(indexes);
break;
}
case Operation::RegroupPaired:
{
QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
m_model->regroupPaired(indexes);
break;
}
case Operation::RegroupBookmarks:
{
QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
if (!indexes.isEmpty())
{
PageItemModel::SelectionInfo selectionInfo = m_model->getSelectionInfo(indexes);
const std::map<int, DocumentItem>& documents = m_model->getDocuments();
auto it = documents.find(selectionInfo.firstDocumentIndex);
if (it != documents.end())
{
const pdf::PDFDocument* document = &it->second.document;
SelectBookmarksToRegroupDialog dialog(document, this);
if (dialog.exec() == SelectBookmarksToRegroupDialog::Accepted)
{
std::vector<pdf::PDFInteger> breakPageIndices;
std::vector<const pdf::PDFOutlineItem*> outlineItems = dialog.getSelectedOutlineItems();
// Jakub Melka: Resolve outline items. Try to find an index
// of page of each outline item.
for (const pdf::PDFOutlineItem* item : outlineItems)
{
const pdf::PDFAction* action = item->getAction();
const pdf::PDFActionGoTo* actionGoto = dynamic_cast<const pdf::PDFActionGoTo*>(action);
if (actionGoto)
{
pdf::PDFDestination destination = actionGoto->getDestination();
if (destination.getDestinationType() == pdf::DestinationType::Named)
{
if (const pdf::PDFDestination* targetDestination = document->getCatalog()->getNamedDestination(destination.getName()))
{
destination = *targetDestination;
}
else
{
destination = pdf::PDFDestination();
}
}
if (destination.isValid())
{
const size_t pageIndex = document->getCatalog()->getPageIndexFromPageReference(destination.getPageReference());
if (pageIndex != pdf::PDFCatalog::INVALID_PAGE_INDEX)
{
breakPageIndices.push_back(pageIndex + 1);
}
}
}
}
std::sort(breakPageIndices.begin(), breakPageIndices.end());
breakPageIndices.erase(std::unique(breakPageIndices.begin(), breakPageIndices.end()), breakPageIndices.end());
m_model->regroupBookmarks(indexes, breakPageIndices);
}
}
}
break;
}
case Operation::RegroupAlternatingPages:
{
QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
m_model->regroupAlternatingPages(indexes, false);
break;
}
case Operation::RegroupAlternatingPagesReversed:
{
QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
m_model->regroupAlternatingPages(indexes, true);
break;
}
default:
{
Q_ASSERT(false);
break;
}
}
updateActions();
}
} // namespace pdfdocpage

View File

@ -1,131 +0,0 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDOCPAGEORGANIZER_MAINWINDOW_H
#define PDFDOCPAGEORGANIZER_MAINWINDOW_H
#include "pdficontheme.h"
#include "pageitemmodel.h"
#include "pageitemdelegate.h"
#include <QMainWindow>
#include <QSignalMapper>
namespace Ui
{
class MainWindow;
}
namespace pdfdocpage
{
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget* parent);
virtual ~MainWindow() override;
QSize getMinPageImageSize() const;
QSize getDefaultPageImageSize() const;
QSize getMaxPageImageSize() const;
enum class Operation
{
Clear,
CloneSelection,
RemoveSelection,
ReplaceSelection,
RestoreRemovedItems,
Undo,
Redo,
Cut,
Copy,
Paste,
RotateLeft,
RotateRight,
Group,
Ungroup,
SelectNone,
SelectAll,
SelectEven,
SelectOdd,
SelectPortrait,
SelectLandscape,
InvertSelection,
ZoomIn,
ZoomOut,
Unite,
Separate,
SeparateGrouped,
InsertImage,
InsertEmptyPage,
InsertPDF,
RegroupEvenOdd,
RegroupPaired,
RegroupBookmarks,
RegroupAlternatingPages,
RegroupAlternatingPagesReversed,
GetSource,
About,
PrepareIconTheme
};
private slots:
void on_actionClose_triggered();
void on_actionAddDocuments_triggered();
void onMappedActionTriggered(int actionId);
void updateActions();
private:
void loadSettings();
void saveSettings();
bool insertDocument(const QString& fileName, const QModelIndex& insertIndex);
bool canPerformOperation(Operation operation) const;
void performOperation(Operation operation);
struct Settings
{
QString directory;
};
Ui::MainWindow* ui;
pdf::PDFIconTheme m_iconTheme;
PageItemModel* m_model;
PageItemDelegate* m_delegate;
Settings m_settings;
QSignalMapper m_mapper;
Qt::DropAction m_dropAction;
};
} // namespace pdfdocpage
#endif // PDFDOCPAGEORGANIZER_MAINWINDOW_H

Some files were not shown because too many files have changed in this diff Show More