diff --git a/3rdparty_licenses/libjpeg_README.txt b/3rdparty_licenses/libjpeg_README.txt
index 80b455a..13b245c 100644
--- a/3rdparty_licenses/libjpeg_README.txt
+++ b/3rdparty_licenses/libjpeg_README.txt
@@ -1,371 +1,371 @@
-The Independent JPEG Group's JPEG software
-==========================================
-
-README for release 9d of 12-Jan-2020
-====================================
-
-This distribution contains the ninth public release of the Independent JPEG
-Group's free JPEG software. You are welcome to redistribute this software and
-to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
-
-This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
-Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
-John Korejwa, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi,
-Ge' Weijers, and other members of the Independent JPEG Group.
-
-IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee
-(previously known as JPEG, together with ITU-T SG16).
-
-
-DOCUMENTATION ROADMAP
-=====================
-
-This file contains the following sections:
-
-OVERVIEW General description of JPEG and the IJG software.
-LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
-REFERENCES Where to learn more about JPEG.
-ARCHIVE LOCATIONS Where to find newer versions of this software.
-ACKNOWLEDGMENTS Special thanks.
-FILE FORMAT WARS Software *not* to get.
-TO DO Plans for future IJG releases.
-
-Other documentation files in the distribution are:
-
-User documentation:
- install.txt How to configure and install the IJG software.
- usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
- rdjpgcom, and wrjpgcom.
- *.1 Unix-style man pages for programs (same info as usage.txt).
- wizard.txt Advanced usage instructions for JPEG wizards only.
- change.log Version-to-version change highlights.
-Programmer and internal documentation:
- libjpeg.txt How to use the JPEG library in your own programs.
- example.c Sample code for calling the JPEG library.
- structure.txt Overview of the JPEG library's internal structure.
- filelist.txt Road map of IJG files.
- coderules.txt Coding style rules --- please read if you contribute code.
-
-Please read at least the files install.txt and usage.txt. Some information
-can also be found in the JPEG FAQ (Frequently Asked Questions) article. See
-ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
-
-If you want to understand how the JPEG code works, we suggest reading one or
-more of the REFERENCES, then looking at the documentation files (in roughly
-the order listed) before diving into the code.
-
-
-OVERVIEW
-========
-
-This package contains C software to implement JPEG image encoding, decoding,
-and transcoding. JPEG (pronounced "jay-peg") is a standardized compression
-method for full-color and grayscale images.
-
-This software implements JPEG baseline, extended-sequential, and progressive
-compression processes. Provision is made for supporting all variants of these
-processes, although some uncommon parameter settings aren't implemented yet.
-We have made no provision for supporting the hierarchical or lossless
-processes defined in the standard.
-
-We provide a set of library routines for reading and writing JPEG image files,
-plus two sample applications "cjpeg" and "djpeg", which use the library to
-perform conversion between JPEG and some other popular image file formats.
-The library is intended to be reused in other applications.
-
-In order to support file conversion and viewing software, we have included
-considerable functionality beyond the bare JPEG coding/decoding capability;
-for example, the color quantization modules are not strictly part of JPEG
-decoding, but they are essential for output to colormapped file formats or
-colormapped displays. These extra functions can be compiled out of the
-library if not required for a particular application.
-
-We have also included "jpegtran", a utility for lossless transcoding between
-different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
-applications for inserting and extracting textual comments in JFIF files.
-
-The emphasis in designing this software has been on achieving portability and
-flexibility, while also making it fast enough to be useful. In particular,
-the software is not intended to be read as a tutorial on JPEG. (See the
-REFERENCES section for introductory material.) Rather, it is intended to
-be reliable, portable, industrial-strength code. We do not claim to have
-achieved that goal in every aspect of the software, but we strive for it.
-
-We welcome the use of this software as a component of commercial products.
-No royalty is required, but we do ask for an acknowledgement in product
-documentation, as described under LEGAL ISSUES.
-
-
-LEGAL ISSUES
-============
-
-In plain English:
-
-1. We don't promise that this software works. (But if you find any bugs,
- please let us know!)
-2. You can use this software for whatever you want. You don't have to pay us.
-3. You may not pretend that you wrote this software. If you use it in a
- program, you must acknowledge somewhere in your documentation that
- you've used the IJG code.
-
-In legalese:
-
-The authors make NO WARRANTY or representation, either express or implied,
-with respect to this software, its quality, accuracy, merchantability, or
-fitness for a particular purpose. This software is provided "AS IS", and you,
-its user, assume the entire risk as to its quality and accuracy.
-
-This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
-All Rights Reserved except as specified below.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-software (or portions thereof) for any purpose, without fee, subject to these
-conditions:
-(1) If any part of the source code for this software is distributed, then this
-README file must be included, with this copyright and no-warranty notice
-unaltered; and any additions, deletions, or changes to the original files
-must be clearly indicated in accompanying documentation.
-(2) If only executable code is distributed, then the accompanying
-documentation must state that "this software is based in part on the work of
-the Independent JPEG Group".
-(3) Permission for use of this software is granted only if the user accepts
-full responsibility for any undesirable consequences; the authors accept
-NO LIABILITY for damages of any kind.
-
-These conditions apply to any software derived from or based on the IJG code,
-not just to the unmodified library. If you use our work, you ought to
-acknowledge us.
-
-Permission is NOT granted for the use of any IJG author's name or company name
-in advertising or publicity relating to this software or products derived from
-it. This software may be referred to only as "the Independent JPEG Group's
-software".
-
-We specifically permit and encourage the use of this software as the basis of
-commercial products, provided that all warranty or liability claims are
-assumed by the product vendor.
-
-
-The Unix configuration script "configure" was produced with GNU Autoconf.
-It is copyright by the Free Software Foundation but is freely distributable.
-The same holds for its supporting scripts (config.guess, config.sub,
-ltmain.sh). Another support script, install-sh, is copyright by X Consortium
-but is also freely distributable.
-
-
-REFERENCES
-==========
-
-We recommend reading one or more of these references before trying to
-understand the innards of the JPEG software.
-
-The best short technical introduction to the JPEG compression algorithm is
- Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
- Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
-(Adjacent articles in that issue discuss MPEG motion picture compression,
-applications of JPEG, and related topics.) If you don't have the CACM issue
-handy, a PDF file containing a revised version of Wallace's article is
-available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually
-a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
-omits the sample images that appeared in CACM, but it includes corrections
-and some added material. Note: the Wallace article is copyright ACM and IEEE,
-and it may not be used for commercial purposes.
-
-A somewhat less technical, more leisurely introduction to JPEG can be found in
-"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
-M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides
-good explanations and example C code for a multitude of compression methods
-including JPEG. It is an excellent source if you are comfortable reading C
-code but don't know much about data compression in general. The book's JPEG
-sample code is far from industrial-strength, but when you are ready to look
-at a full implementation, you've got one here...
-
-The best currently available description of JPEG is the textbook "JPEG Still
-Image Data Compression Standard" by William B. Pennebaker and Joan L.
-Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
-Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG
-standards (DIS 10918-1 and draft DIS 10918-2).
-Although this is by far the most detailed and comprehensive exposition of
-JPEG publicly available, we point out that it is still missing an explanation
-of the most essential properties and algorithms of the underlying DCT
-technology.
-If you think that you know about DCT-based JPEG after reading this book,
-then you are in delusion. The real fundamentals and corresponding potential
-of DCT-based JPEG are not publicly known so far, and that is the reason for
-all the mistaken developments taking place in the image coding domain.
-
-The original JPEG standard is divided into two parts, Part 1 being the actual
-specification, while Part 2 covers compliance testing methods. Part 1 is
-titled "Digital Compression and Coding of Continuous-tone Still Images,
-Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
-10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
-Continuous-tone Still Images, Part 2: Compliance testing" and has document
-numbers ISO/IEC IS 10918-2, ITU-T T.83.
-IJG JPEG 8 introduced an implementation of the JPEG SmartScale extension
-which is specified in two documents: A contributed document at ITU and ISO
-with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced
-Image Coding", April 2006, Geneva, Switzerland. The latest version of this
-document is Revision 3. And a contributed document ISO/IEC JTC1/SC29/WG1 N
-5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany.
-IJG JPEG 9 introduces a reversible color transform for improved lossless
-compression which is described in a contributed document ISO/IEC JTC1/SC29/
-WG1 N 6080 with title "JPEG 9 Lossless Coding", June/July 2012, Paris,
-France.
-
-The JPEG standard does not specify all details of an interchangeable file
-format. For the omitted details we follow the "JFIF" conventions, version 2.
-JFIF version 1 has been adopted as Recommendation ITU-T T.871 (05/2011) :
-Information technology - Digital compression and coding of continuous-tone
-still images: JPEG File Interchange Format (JFIF). It is available as a
-free download in PDF file format from http://www.itu.int/rec/T-REC-T.871.
-A PDF file of the older JFIF document is available at
-http://www.w3.org/Graphics/JPEG/jfif3.pdf.
-
-The TIFF 6.0 file format specification can be obtained by FTP from
-ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme
-found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
-IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
-Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
-(Compression tag 7). Copies of this Note can be obtained from
-http://www.ijg.org/files/. It is expected that the next revision
-of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
-Although IJG's own code does not support TIFF/JPEG, the free libtiff library
-uses our library to implement TIFF/JPEG per the Note.
-
-
-ARCHIVE LOCATIONS
-=================
-
-The "official" archive site for this software is www.ijg.org.
-The most recent released version can always be found there in
-directory "files". This particular version will be archived as
-http://www.ijg.org/files/jpegsrc.v9d.tar.gz, and in Windows-compatible
-"zip" archive format as http://www.ijg.org/files/jpegsr9d.zip.
-
-The JPEG FAQ (Frequently Asked Questions) article is a source of some
-general information about JPEG.
-It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
-and other news.answers archive sites, including the official news.answers
-archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
-If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu
-with body
- send usenet/news.answers/jpeg-faq/part1
- send usenet/news.answers/jpeg-faq/part2
-
-
-ACKNOWLEDGMENTS
-===============
-
-Thank to Juergen Bruder for providing me with a copy of the common DCT
-algorithm article, only to find out that I had come to the same result
-in a more direct and comprehensible way with a more generative approach.
-
-Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the
-ITU JPEG (Study Group 16) meeting in Geneva, Switzerland.
-
-Thank to Thomas Wiegand and Gary Sullivan for inviting me to the
-Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland.
-
-Thank to Thomas Richter and Daniel Lee for inviting me to the
-ISO/IEC JTC1/SC29/WG1 (previously known as JPEG, together with ITU-T SG16)
-meeting in Berlin, Germany.
-
-Thank to John Korejwa and Massimo Ballerini for inviting me to
-fruitful consultations in Boston, MA and Milan, Italy.
-
-Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther
-Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel
-for corresponding business development.
-
-Thank to Nico Zschach and Dirk Stelling of the technical support team
-at the Digital Images company in Halle for providing me with extra
-equipment for configuration tests.
-
-Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful
-communication about JPEG configuration in Sigma Photo Pro software.
-
-Thank to Andrew Finkenstadt for hosting the ijg.org site.
-
-Thank to Thomas G. Lane for the original design and development of
-this singular software package.
-
-Thank to Lars Goehler, Andreas Heinecke, Sebastian Fuss, Yvonne Roebert,
-Andrej Werner, and Ulf-Dietrich Braumann for support and public relations.
-
-
-FILE FORMAT WARS
-================
-
-The ISO/IEC JTC1/SC29/WG1 standards committee (previously known as JPEG,
-together with ITU-T SG16) currently promotes different formats containing
-the name "JPEG" which is misleading because these formats are incompatible
-with original DCT-based JPEG and are based on faulty technologies.
-IJG therefore does not and will not support such momentary mistakes
-(see REFERENCES).
-There exist also distributions under the name "OpenJPEG" promoting such
-kind of formats which is misleading because they don't support original
-JPEG images.
-We have no sympathy for the promotion of inferior formats. Indeed, one of
-the original reasons for developing this free software was to help force
-convergence on common, interoperable format standards for JPEG files.
-Don't use an incompatible file format!
-(In any case, our decoder will remain capable of reading existing JPEG
-image files indefinitely.)
-
-The ISO committee pretends to be "responsible for the popular JPEG" in their
-public reports which is not true because they don't respond to actual
-requirements for the maintenance of the original JPEG specification.
-Furthermore, the ISO committee pretends to "ensure interoperability" with
-their standards which is not true because their "standards" support only
-application-specific and proprietary use cases and contain mathematically
-incorrect code.
-
-There are currently different distributions in circulation containing the
-name "libjpeg" which is misleading because they don't have the features and
-are incompatible with formats supported by actual IJG libjpeg distributions.
-One of those fakes is released by members of the ISO committee and just uses
-the name of libjpeg for misdirection of people, similar to the abuse of the
-name JPEG as described above, while having nothing in common with actual IJG
-libjpeg distributions and containing mathematically incorrect code.
-The other one claims to be a "derivative" or "fork" of the original libjpeg,
-but violates the license conditions as described under LEGAL ISSUES above
-and violates basic C programming properties.
-We have no sympathy for the release of misleading, incorrect and illegal
-distributions derived from obsolete code bases.
-Don't use an obsolete code base!
-
-According to the UCC (Uniform Commercial Code) law, IJG has the lawful and
-legal right to foreclose on certain standardization bodies and other
-institutions or corporations that knowingly perform substantial and
-systematic deceptive acts and practices, fraud, theft, and damaging of the
-value of the people of this planet without their knowing, willing and
-intentional consent.
-The titles, ownership, and rights of these institutions and all their assets
-are now duly secured and held in trust for the free people of this planet.
-People of the planet, on every country, may have a financial interest in
-the assets of these former principals, agents, and beneficiaries of the
-foreclosed institutions and corporations.
-IJG asserts what is: that each man, woman, and child has unalienable value
-and rights granted and deposited in them by the Creator and not any one of
-the people is subordinate to any artificial principality, corporate fiction
-or the special interest of another without their appropriate knowing,
-willing and intentional consent made by contract or accommodation agreement.
-IJG expresses that which already was.
-The people have already determined and demanded that public administration
-entities, national governments, and their supporting judicial systems must
-be fully transparent, accountable, and liable.
-IJG has secured the value for all concerned free people of the planet.
-
-A partial list of foreclosed institutions and corporations ("Hall of Shame")
-is currently prepared and will be published later.
-
-
-TO DO
-=====
-
-Version 9 is the second release of a new generation JPEG standard
-to overcome the limitations of the original JPEG specification,
-and is the first true source reference JPEG codec.
-More features are being prepared for coming releases...
-
-Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.
+The Independent JPEG Group's JPEG software
+==========================================
+
+README for release 9d of 12-Jan-2020
+====================================
+
+This distribution contains the ninth public release of the Independent JPEG
+Group's free JPEG software. You are welcome to redistribute this software and
+to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
+
+This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
+Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
+John Korejwa, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi,
+Ge' Weijers, and other members of the Independent JPEG Group.
+
+IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee
+(previously known as JPEG, together with ITU-T SG16).
+
+
+DOCUMENTATION ROADMAP
+=====================
+
+This file contains the following sections:
+
+OVERVIEW General description of JPEG and the IJG software.
+LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
+REFERENCES Where to learn more about JPEG.
+ARCHIVE LOCATIONS Where to find newer versions of this software.
+ACKNOWLEDGMENTS Special thanks.
+FILE FORMAT WARS Software *not* to get.
+TO DO Plans for future IJG releases.
+
+Other documentation files in the distribution are:
+
+User documentation:
+ install.txt How to configure and install the IJG software.
+ usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
+ rdjpgcom, and wrjpgcom.
+ *.1 Unix-style man pages for programs (same info as usage.txt).
+ wizard.txt Advanced usage instructions for JPEG wizards only.
+ change.log Version-to-version change highlights.
+Programmer and internal documentation:
+ libjpeg.txt How to use the JPEG library in your own programs.
+ example.c Sample code for calling the JPEG library.
+ structure.txt Overview of the JPEG library's internal structure.
+ filelist.txt Road map of IJG files.
+ coderules.txt Coding style rules --- please read if you contribute code.
+
+Please read at least the files install.txt and usage.txt. Some information
+can also be found in the JPEG FAQ (Frequently Asked Questions) article. See
+ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
+
+If you want to understand how the JPEG code works, we suggest reading one or
+more of the REFERENCES, then looking at the documentation files (in roughly
+the order listed) before diving into the code.
+
+
+OVERVIEW
+========
+
+This package contains C software to implement JPEG image encoding, decoding,
+and transcoding. JPEG (pronounced "jay-peg") is a standardized compression
+method for full-color and grayscale images.
+
+This software implements JPEG baseline, extended-sequential, and progressive
+compression processes. Provision is made for supporting all variants of these
+processes, although some uncommon parameter settings aren't implemented yet.
+We have made no provision for supporting the hierarchical or lossless
+processes defined in the standard.
+
+We provide a set of library routines for reading and writing JPEG image files,
+plus two sample applications "cjpeg" and "djpeg", which use the library to
+perform conversion between JPEG and some other popular image file formats.
+The library is intended to be reused in other applications.
+
+In order to support file conversion and viewing software, we have included
+considerable functionality beyond the bare JPEG coding/decoding capability;
+for example, the color quantization modules are not strictly part of JPEG
+decoding, but they are essential for output to colormapped file formats or
+colormapped displays. These extra functions can be compiled out of the
+library if not required for a particular application.
+
+We have also included "jpegtran", a utility for lossless transcoding between
+different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
+applications for inserting and extracting textual comments in JFIF files.
+
+The emphasis in designing this software has been on achieving portability and
+flexibility, while also making it fast enough to be useful. In particular,
+the software is not intended to be read as a tutorial on JPEG. (See the
+REFERENCES section for introductory material.) Rather, it is intended to
+be reliable, portable, industrial-strength code. We do not claim to have
+achieved that goal in every aspect of the software, but we strive for it.
+
+We welcome the use of this software as a component of commercial products.
+No royalty is required, but we do ask for an acknowledgement in product
+documentation, as described under LEGAL ISSUES.
+
+
+LEGAL ISSUES
+============
+
+In plain English:
+
+1. We don't promise that this software works. (But if you find any bugs,
+ please let us know!)
+2. You can use this software for whatever you want. You don't have to pay us.
+3. You may not pretend that you wrote this software. If you use it in a
+ program, you must acknowledge somewhere in your documentation that
+ you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose. This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library. If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it. This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+The Unix configuration script "configure" was produced with GNU Autoconf.
+It is copyright by the Free Software Foundation but is freely distributable.
+The same holds for its supporting scripts (config.guess, config.sub,
+ltmain.sh). Another support script, install-sh, is copyright by X Consortium
+but is also freely distributable.
+
+
+REFERENCES
+==========
+
+We recommend reading one or more of these references before trying to
+understand the innards of the JPEG software.
+
+The best short technical introduction to the JPEG compression algorithm is
+ Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+ Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
+(Adjacent articles in that issue discuss MPEG motion picture compression,
+applications of JPEG, and related topics.) If you don't have the CACM issue
+handy, a PDF file containing a revised version of Wallace's article is
+available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually
+a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
+omits the sample images that appeared in CACM, but it includes corrections
+and some added material. Note: the Wallace article is copyright ACM and IEEE,
+and it may not be used for commercial purposes.
+
+A somewhat less technical, more leisurely introduction to JPEG can be found in
+"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
+M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides
+good explanations and example C code for a multitude of compression methods
+including JPEG. It is an excellent source if you are comfortable reading C
+code but don't know much about data compression in general. The book's JPEG
+sample code is far from industrial-strength, but when you are ready to look
+at a full implementation, you've got one here...
+
+The best currently available description of JPEG is the textbook "JPEG Still
+Image Data Compression Standard" by William B. Pennebaker and Joan L.
+Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
+Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG
+standards (DIS 10918-1 and draft DIS 10918-2).
+Although this is by far the most detailed and comprehensive exposition of
+JPEG publicly available, we point out that it is still missing an explanation
+of the most essential properties and algorithms of the underlying DCT
+technology.
+If you think that you know about DCT-based JPEG after reading this book,
+then you are in delusion. The real fundamentals and corresponding potential
+of DCT-based JPEG are not publicly known so far, and that is the reason for
+all the mistaken developments taking place in the image coding domain.
+
+The original JPEG standard is divided into two parts, Part 1 being the actual
+specification, while Part 2 covers compliance testing methods. Part 1 is
+titled "Digital Compression and Coding of Continuous-tone Still Images,
+Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
+10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
+Continuous-tone Still Images, Part 2: Compliance testing" and has document
+numbers ISO/IEC IS 10918-2, ITU-T T.83.
+IJG JPEG 8 introduced an implementation of the JPEG SmartScale extension
+which is specified in two documents: A contributed document at ITU and ISO
+with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced
+Image Coding", April 2006, Geneva, Switzerland. The latest version of this
+document is Revision 3. And a contributed document ISO/IEC JTC1/SC29/WG1 N
+5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany.
+IJG JPEG 9 introduces a reversible color transform for improved lossless
+compression which is described in a contributed document ISO/IEC JTC1/SC29/
+WG1 N 6080 with title "JPEG 9 Lossless Coding", June/July 2012, Paris,
+France.
+
+The JPEG standard does not specify all details of an interchangeable file
+format. For the omitted details we follow the "JFIF" conventions, version 2.
+JFIF version 1 has been adopted as Recommendation ITU-T T.871 (05/2011) :
+Information technology - Digital compression and coding of continuous-tone
+still images: JPEG File Interchange Format (JFIF). It is available as a
+free download in PDF file format from http://www.itu.int/rec/T-REC-T.871.
+A PDF file of the older JFIF document is available at
+http://www.w3.org/Graphics/JPEG/jfif3.pdf.
+
+The TIFF 6.0 file format specification can be obtained by FTP from
+ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme
+found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
+IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
+Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
+(Compression tag 7). Copies of this Note can be obtained from
+http://www.ijg.org/files/. It is expected that the next revision
+of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
+Although IJG's own code does not support TIFF/JPEG, the free libtiff library
+uses our library to implement TIFF/JPEG per the Note.
+
+
+ARCHIVE LOCATIONS
+=================
+
+The "official" archive site for this software is www.ijg.org.
+The most recent released version can always be found there in
+directory "files". This particular version will be archived as
+http://www.ijg.org/files/jpegsrc.v9d.tar.gz, and in Windows-compatible
+"zip" archive format as http://www.ijg.org/files/jpegsr9d.zip.
+
+The JPEG FAQ (Frequently Asked Questions) article is a source of some
+general information about JPEG.
+It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
+and other news.answers archive sites, including the official news.answers
+archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
+If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu
+with body
+ send usenet/news.answers/jpeg-faq/part1
+ send usenet/news.answers/jpeg-faq/part2
+
+
+ACKNOWLEDGMENTS
+===============
+
+Thank to Juergen Bruder for providing me with a copy of the common DCT
+algorithm article, only to find out that I had come to the same result
+in a more direct and comprehensible way with a more generative approach.
+
+Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the
+ITU JPEG (Study Group 16) meeting in Geneva, Switzerland.
+
+Thank to Thomas Wiegand and Gary Sullivan for inviting me to the
+Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland.
+
+Thank to Thomas Richter and Daniel Lee for inviting me to the
+ISO/IEC JTC1/SC29/WG1 (previously known as JPEG, together with ITU-T SG16)
+meeting in Berlin, Germany.
+
+Thank to John Korejwa and Massimo Ballerini for inviting me to
+fruitful consultations in Boston, MA and Milan, Italy.
+
+Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther
+Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel
+for corresponding business development.
+
+Thank to Nico Zschach and Dirk Stelling of the technical support team
+at the Digital Images company in Halle for providing me with extra
+equipment for configuration tests.
+
+Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful
+communication about JPEG configuration in Sigma Photo Pro software.
+
+Thank to Andrew Finkenstadt for hosting the ijg.org site.
+
+Thank to Thomas G. Lane for the original design and development of
+this singular software package.
+
+Thank to Lars Goehler, Andreas Heinecke, Sebastian Fuss, Yvonne Roebert,
+Andrej Werner, and Ulf-Dietrich Braumann for support and public relations.
+
+
+FILE FORMAT WARS
+================
+
+The ISO/IEC JTC1/SC29/WG1 standards committee (previously known as JPEG,
+together with ITU-T SG16) currently promotes different formats containing
+the name "JPEG" which is misleading because these formats are incompatible
+with original DCT-based JPEG and are based on faulty technologies.
+IJG therefore does not and will not support such momentary mistakes
+(see REFERENCES).
+There exist also distributions under the name "OpenJPEG" promoting such
+kind of formats which is misleading because they don't support original
+JPEG images.
+We have no sympathy for the promotion of inferior formats. Indeed, one of
+the original reasons for developing this free software was to help force
+convergence on common, interoperable format standards for JPEG files.
+Don't use an incompatible file format!
+(In any case, our decoder will remain capable of reading existing JPEG
+image files indefinitely.)
+
+The ISO committee pretends to be "responsible for the popular JPEG" in their
+public reports which is not true because they don't respond to actual
+requirements for the maintenance of the original JPEG specification.
+Furthermore, the ISO committee pretends to "ensure interoperability" with
+their standards which is not true because their "standards" support only
+application-specific and proprietary use cases and contain mathematically
+incorrect code.
+
+There are currently different distributions in circulation containing the
+name "libjpeg" which is misleading because they don't have the features and
+are incompatible with formats supported by actual IJG libjpeg distributions.
+One of those fakes is released by members of the ISO committee and just uses
+the name of libjpeg for misdirection of people, similar to the abuse of the
+name JPEG as described above, while having nothing in common with actual IJG
+libjpeg distributions and containing mathematically incorrect code.
+The other one claims to be a "derivative" or "fork" of the original libjpeg,
+but violates the license conditions as described under LEGAL ISSUES above
+and violates basic C programming properties.
+We have no sympathy for the release of misleading, incorrect and illegal
+distributions derived from obsolete code bases.
+Don't use an obsolete code base!
+
+According to the UCC (Uniform Commercial Code) law, IJG has the lawful and
+legal right to foreclose on certain standardization bodies and other
+institutions or corporations that knowingly perform substantial and
+systematic deceptive acts and practices, fraud, theft, and damaging of the
+value of the people of this planet without their knowing, willing and
+intentional consent.
+The titles, ownership, and rights of these institutions and all their assets
+are now duly secured and held in trust for the free people of this planet.
+People of the planet, on every country, may have a financial interest in
+the assets of these former principals, agents, and beneficiaries of the
+foreclosed institutions and corporations.
+IJG asserts what is: that each man, woman, and child has unalienable value
+and rights granted and deposited in them by the Creator and not any one of
+the people is subordinate to any artificial principality, corporate fiction
+or the special interest of another without their appropriate knowing,
+willing and intentional consent made by contract or accommodation agreement.
+IJG expresses that which already was.
+The people have already determined and demanded that public administration
+entities, national governments, and their supporting judicial systems must
+be fully transparent, accountable, and liable.
+IJG has secured the value for all concerned free people of the planet.
+
+A partial list of foreclosed institutions and corporations ("Hall of Shame")
+is currently prepared and will be published later.
+
+
+TO DO
+=====
+
+Version 9 is the second release of a new generation JPEG standard
+to overcome the limitations of the original JPEG specification,
+and is the first true source reference JPEG codec.
+More features are being prepared for coming releases...
+
+Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.
diff --git a/CodeGenerator/CodeGenerator.pro b/CodeGenerator/CodeGenerator.pro
index ab4875a..c7da918 100644
--- a/CodeGenerator/CodeGenerator.pro
+++ b/CodeGenerator/CodeGenerator.pro
@@ -1,53 +1,53 @@
-# Copyright (C) 2018-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 .
-
-QT += core gui xml
-
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-CONFIG += c++11
-
-# The following define makes your compiler emit warnings if you use
-# any Qt feature that has been marked deprecated (the exact warnings
-# depend on your compiler). Please consult the documentation of the
-# deprecated API in order to know how to port your code away from it.
-DEFINES += QT_DEPRECATED_WARNINGS
-
-# You can also make your code fail to compile if it uses deprecated APIs.
-# In order to do so, uncomment the following line.
-# You can also select to disable deprecated APIs only up to a certain version of Qt.
-#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
-QMAKE_CXXFLAGS += /std:c++latest /utf-8
-
-DESTDIR = $$OUT_PWD/..
-
-LIBS += -L$$OUT_PWD/..
-
-
-SOURCES += \
- codegenerator.cpp \
- main.cpp \
- generatormainwindow.cpp
-
-HEADERS += \
- codegenerator.h \
- generatormainwindow.h
-
-FORMS += \
- generatormainwindow.ui
-
+# Copyright (C) 2018-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 .
+
+QT += core gui xml
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++11
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+QMAKE_CXXFLAGS += /std:c++latest /utf-8
+
+DESTDIR = $$OUT_PWD/..
+
+LIBS += -L$$OUT_PWD/..
+
+
+SOURCES += \
+ codegenerator.cpp \
+ main.cpp \
+ generatormainwindow.cpp
+
+HEADERS += \
+ codegenerator.h \
+ generatormainwindow.h
+
+FORMS += \
+ generatormainwindow.ui
+
diff --git a/CodeGenerator/codegenerator.cpp b/CodeGenerator/codegenerator.cpp
index ec3e905..5e2ebe9 100644
--- a/CodeGenerator/codegenerator.cpp
+++ b/CodeGenerator/codegenerator.cpp
@@ -1,1402 +1,1402 @@
-// Copyright (C) 2020-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 .
-
-#include "codegenerator.h"
-
-#include
-#include
-#include
-#include
-#include
-
-namespace codegen
-{
-
-GeneratedCodeStorage::GeneratedCodeStorage(QObject* parent) :
- BaseClass(parent)
-{
-
-}
-
-QObjectList GeneratedCodeStorage::getFunctions() const
-{
- return m_functions;
-}
-
-void GeneratedCodeStorage::setFunctions(const QObjectList& functions)
-{
- m_functions = functions;
-
- auto comparator = [](const QObject* left, const QObject* right)
- {
- const GeneratedFunction* leftFunction = qobject_cast(left);
- const GeneratedFunction* rightFunction = qobject_cast(right);
- return leftFunction->getFunctionName() < rightFunction->getFunctionName();
- };
- std::sort(m_functions.begin(), m_functions.end(), comparator);
-}
-
-GeneratedFunction* GeneratedCodeStorage::addFunction(const QString& name)
-{
- GeneratedFunction* function = new GeneratedFunction(this);
- function->setFunctionName(name);
- m_functions.append(function);
- return function;
-}
-
-GeneratedFunction* GeneratedCodeStorage::addFunction(GeneratedFunction* function)
-{
- function->setParent(this);
- m_functions.append(function);
- return function;
-}
-
-void GeneratedCodeStorage::removeFunction(GeneratedFunction* function)
-{
- function->deleteLater();
- m_functions.removeOne(function);
-}
-
-void GeneratedCodeStorage::generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
-{
- stream << Qt::endl << Qt::endl;
-
- for (const QObject* object : m_functions)
- {
- const GeneratedFunction* generatedFunction = qobject_cast(object);
- generatedFunction->generateCode(stream, parameters);
- stream << Qt::endl << Qt::endl;
- }
-}
-
-QObject* Serializer::load(const QDomElement& element, QObject* parent)
-{
- QString className = element.attribute("class");
- const int metaTypeId = QMetaType::type(className.toLatin1());
- const QMetaObject* metaObject = QMetaType::metaObjectForType(metaTypeId);
-
- if (metaObject)
- {
- QObject* deserializedObject = metaObject->newInstance(Q_ARG(QObject*, parent));
-
- const int propertyCount = metaObject->propertyCount();
- for (int i = 0; i < propertyCount; ++i)
- {
- QMetaProperty property = metaObject->property(i);
- if (property.isWritable())
- {
- // Find, if property was serialized
- QDomElement propertyElement;
- QDomNodeList children = element.childNodes();
- for (int i = 0; i < children.count(); ++i)
- {
- QDomNode child = children.item(i);
- if (child.isElement())
- {
- QDomElement childElement = child.toElement();
- QString attributeName = childElement.attribute("name");
- if (attributeName == property.name())
- {
- propertyElement = child.toElement();
- break;
- }
- }
- }
-
- if (!propertyElement.isNull())
- {
- // Deserialize the element
- if (property.isEnumType())
- {
- QMetaEnum metaEnum = property.enumerator();
- Q_ASSERT(metaEnum.isValid());
- property.write(deserializedObject, metaEnum.keyToValue(propertyElement.text().toLatin1().data()));
- }
- else if (property.userType() == qMetaTypeId())
- {
- QObjectList objectList;
- QDomNodeList children = propertyElement.childNodes();
- for (int i = 0; i < children.count(); ++i)
- {
- QDomNode node = children.item(i);
- if (node.isElement())
- {
- QDomElement element = node.toElement();
- if (QObject* object = Serializer::load(element, deserializedObject))
- {
- objectList.append(object);
- }
- }
- }
-
- property.write(deserializedObject, QVariant::fromValue(qMove(objectList)));
- }
- else
- {
- QVariant value = propertyElement.text();
- property.write(deserializedObject, value);
- }
- }
- }
- }
-
- return deserializedObject;
- }
-
- return nullptr;
-}
-
-void Serializer::store(QObject* object, QDomElement& element)
-{
- Q_ASSERT(object);
-
- const QMetaObject* metaObject = object->metaObject();
- element.setAttribute("class", QString(metaObject->className()));
-
- const int propertyCount = metaObject->propertyCount();
- if (propertyCount > 0)
- {
- for (int i = 0; i < propertyCount; ++i)
- {
- QMetaProperty property = metaObject->property(i);
- if (property.isReadable())
- {
- QDomElement propertyElement = element.ownerDocument().createElement("property");
- element.appendChild(propertyElement);
- propertyElement.setAttribute("name", property.name());
-
- QVariant value = property.read(object);
- if (property.isEnumType())
- {
- QMetaEnum metaEnum = property.enumerator();
- Q_ASSERT(metaEnum.isValid());
- propertyElement.appendChild(propertyElement.ownerDocument().createTextNode(metaEnum.valueToKey(value.toInt())));
- }
- else if (value.canConvert())
- {
- QObjectList objectList = value.value();
- for (QObject* currentObject : objectList)
- {
- QDomElement objectElement = element.ownerDocument().createElement("QObject");
- propertyElement.appendChild(objectElement);
- Serializer::store(currentObject, objectElement);
- }
- }
- else
- {
- propertyElement.appendChild(propertyElement.ownerDocument().createTextNode(value.toString()));
- }
- }
- }
- }
-}
-
-QObject* Serializer::clone(QObject* object, QObject* parent)
-{
- QDomDocument document;
- QDomElement rootElement = document.createElement("root");
- document.appendChild(rootElement);
- Serializer::store(object, rootElement);
- return Serializer::load(rootElement, parent);
-}
-
-CodeGenerator::CodeGenerator(QObject* parent) :
- BaseClass(parent)
-{
- qRegisterMetaType("codegen::GeneratedCodeStorage");
- qRegisterMetaType("codegen::GeneratedFunction");
- qRegisterMetaType("codegen::GeneratedBase");
- qRegisterMetaType("codegen::GeneratedParameter");
- qRegisterMetaType("codegen::GeneratedPDFObject");
- qRegisterMetaType("codegen::GeneratedAction");
- qRegisterMetaType("QObjectList");
-}
-
-void CodeGenerator::initialize()
-{
- m_storage = new GeneratedCodeStorage(this);
-}
-
-void CodeGenerator::load(const QDomDocument& document)
-{
- delete m_storage;
- m_storage = nullptr;
-
- m_storage = qobject_cast(Serializer::load(document.firstChildElement("root"), this));
-}
-
-void CodeGenerator::store(QDomDocument& document)
-{
- if (m_storage)
- {
- QDomElement rootElement = document.createElement("root");
- document.appendChild(rootElement);
- Serializer::store(m_storage, rootElement);
- }
-}
-
-void CodeGenerator::generateCode(QString headerName, QString sourceName) const
-{
- QString startMark = "/* START GENERATED CODE */";
- QString endMark = "/* END GENERATED CODE */";
- QString className = "PDFDocumentBuilder";
- const int indent = 4;
-
- QFile headerFile(headerName);
- if (headerFile.exists())
- {
- if (headerFile.open(QFile::ReadOnly | QFile::Text))
- {
- QString utfCode = QString::fromUtf8(headerFile.readAll());
- headerFile.close();
-
- int startIndex = utfCode.indexOf(startMark, Qt::CaseSensitive) + startMark.length();
- int endIndex = utfCode.indexOf(endMark, Qt::CaseSensitive);
-
- QString frontPart = utfCode.left(startIndex);
- QString backPart = utfCode.mid(endIndex);
- QString headerGeneratedCode = generateHeader(indent);
- QString allCode = frontPart + headerGeneratedCode + backPart;
-
- headerFile.open(QFile::WriteOnly | QFile::Truncate);
- headerFile.write(allCode.toUtf8());
- headerFile.close();
- }
- }
-
- QFile sourceFile(sourceName);
- if (sourceFile.exists())
- {
- if (sourceFile.open(QFile::ReadOnly | QFile::Text))
- {
- QString utfCode = QString::fromUtf8(sourceFile.readAll());
- sourceFile.close();
-
- int startIndex = utfCode.indexOf(startMark, Qt::CaseSensitive) + startMark.length();
- int endIndex = utfCode.indexOf(endMark, Qt::CaseSensitive);
-
- QString frontPart = utfCode.left(startIndex);
- QString backPart = utfCode.mid(endIndex);
- QString sourceGeneratedCode = generateSource(className, indent);
- QString allCode = frontPart + sourceGeneratedCode + backPart;
-
- sourceFile.open(QFile::WriteOnly | QFile::Truncate);
- sourceFile.write(allCode.toUtf8());
- sourceFile.close();
- }
- }
-}
-
-QString CodeGenerator::generateHeader(int indent) const
-{
- QByteArray ba;
- {
- QTextStream stream(&ba, QIODevice::WriteOnly);
- stream.setCodec("UTF-8");
- stream.setRealNumberPrecision(3);
- stream.setRealNumberNotation(QTextStream::FixedNotation);
-
- CodeGeneratorParameters parameters;
- parameters.header = true;
- parameters.indent = indent;
- m_storage->generateCode(stream, parameters);
- }
-
- return QString::fromUtf8(ba);
-}
-
-QString CodeGenerator::generateSource(QString className, int indent) const
-{
- QByteArray ba;
- {
- QTextStream stream(&ba, QIODevice::WriteOnly);
- stream.setCodec("UTF-8");
- stream.setRealNumberPrecision(3);
- stream.setRealNumberNotation(QTextStream::FixedNotation);
-
- CodeGeneratorParameters parameters;
- parameters.header = false;
- parameters.indent = indent;
- parameters.className = className;
- m_storage->generateCode(stream, parameters);
- }
-
- return QString::fromUtf8(ba);
-}
-
-GeneratedFunction::GeneratedFunction(QObject* parent) :
- BaseClass(parent)
-{
-
-}
-
-QString GeneratedFunction::getFunctionTypeString() const
-{
- return Serializer::convertEnumToString(m_functionType);
-}
-
-void GeneratedFunction::setFunctionTypeString(const QString& string)
-{
- Serializer::convertStringToEnum(string, m_functionType);
-}
-
-GeneratedFunction::FunctionType GeneratedFunction::getFunctionType() const
-{
- return m_functionType;
-}
-
-void GeneratedFunction::setFunctionType(const FunctionType& functionType)
-{
- m_functionType = functionType;
-}
-
-QString GeneratedFunction::getFunctionName() const
-{
- return m_functionName;
-}
-
-void GeneratedFunction::setFunctionName(const QString& functionName)
-{
- m_functionName = functionName;
-}
-
-QString GeneratedFunction::getFunctionDescription() const
-{
- return m_functionDescription;
-}
-
-void GeneratedFunction::setFunctionDescription(const QString& functionDescription)
-{
- m_functionDescription = functionDescription;
-}
-
-GeneratedFunction* GeneratedFunction::clone(QObject* parent)
-{
- return qobject_cast(Serializer::clone(this, parent));
-}
-
-void GeneratedFunction::generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
-{
- QStringList parameterCaptions;
- QStringList parameterTexts;
- std::function gatherParameters = [&](const GeneratedBase* object, Pass pass)
- {
- if (pass != Pass::Enter)
- {
- return;
- }
-
- if (const GeneratedParameter* generatedParameter = qobject_cast(object))
- {
- parameterCaptions << QString("%1 %2").arg(generatedParameter->getParameterName(), generatedParameter->getParameterDescription());
- parameterTexts << QString("%1 %2").arg(getCppType(generatedParameter->getParameterDataType()), generatedParameter->getParameterName());
- }
- };
- applyFunctor(gatherParameters);
-
- if (parameterTexts.isEmpty())
- {
- parameterTexts << "";
- }
-
- if (parameters.header)
- {
- // Generate header source code
-
- // Function comments
- for (const QString& string : getFormattedTextWithLayout("/// ", "/// ", getFunctionDescription(), parameters.indent))
- {
- stream << string << Qt::endl;
- }
-
- // Function parameter comments
- for (const QString& parameterCaption : parameterCaptions)
- {
- for (const QString& string : getFormattedTextWithLayout("/// \\param ", "/// ", parameterCaption, parameters.indent))
- {
- stream << string << Qt::endl;
- }
- }
-
- // Function declaration
- QString functionHeader = QString("%1 %2(").arg(getCppType(getReturnType()), getFunctionName());
- QString functionHeaderNext(functionHeader.length(), QChar(QChar::Space));
- QString functionFooter = QString(");");
-
- for (QString& str : parameterTexts)
- {
- str += ",";
- }
- parameterTexts.back().replace(",", functionFooter);
-
- QStringList functionDeclaration = getFormattedTextBlock(functionHeader, functionHeaderNext, parameterTexts, parameters.indent);
- for (const QString& functionDeclarationItem : functionDeclaration)
- {
- stream << functionDeclarationItem << Qt::endl;
- }
- }
- else
- {
- // Generate c++ source code
- QString functionHeader = QString("%1 %2::%3(").arg(getCppType(getReturnType()), parameters.className, getFunctionName());
- QString functionHeaderNext(functionHeader.length(), QChar(QChar::Space));
- QString functionFooter = QString(")");
-
- for (QString& str : parameterTexts)
- {
- str += ",";
- }
- parameterTexts.back().replace(",", functionFooter);
-
- QStringList functionDeclaration = getFormattedTextBlock(functionHeader, functionHeaderNext, parameterTexts, 0);
- for (const QString& functionDeclarationItem : functionDeclaration)
- {
- stream << functionDeclarationItem << Qt::endl;
- }
-
- QString indent(parameters.indent, QChar(QChar::Space));
-
- stream << "{" << Qt::endl;
- stream << indent << "PDFObjectFactory objectBuilder;" << Qt::endl << Qt::endl;
-
- generateSourceCode(stream, parameters);
-
- stream << "}" << Qt::endl;
- }
-}
-
-bool GeneratedFunction::hasField(GeneratedBase::FieldType fieldType) const
-{
- switch (fieldType)
- {
- case FieldType::Name:
- case FieldType::ItemType:
- case FieldType::DataType:
- case FieldType::Description:
- return true;
-
- case FieldType::Value:
- return false;
-
- default:
- break;
- }
-
- return false;
-}
-
-QVariant GeneratedFunction::readField(GeneratedBase::FieldType fieldType) const
-{
- switch (fieldType)
- {
- case FieldType::Name:
- return m_functionName;
- case FieldType::ItemType:
- return int(m_functionType);
- case FieldType::DataType:
- return int(m_returnType);
- case FieldType::Description:
- return m_functionDescription;
-
- case FieldType::Value:
- default:
- break;
- }
-
- return QVariant();
-}
-
-void GeneratedFunction::writeField(GeneratedBase::FieldType fieldType, QVariant value)
-{
- switch (fieldType)
- {
- case FieldType::Name:
- m_functionName = value.toString();
- break;
- case FieldType::ItemType:
- m_functionType = static_cast(value.toInt());
- break;
- case FieldType::DataType:
- m_returnType = static_cast(value.toInt());
- break;
- case FieldType::Description:
- m_functionDescription = value.toString();
- break;
-
- case FieldType::Value:
- default:
- break;
- }
-}
-
-void GeneratedFunction::fillComboBox(QComboBox* comboBox, GeneratedBase::FieldType fieldType)
-{
- switch (fieldType)
- {
- case FieldType::ItemType:
- Serializer::fillComboBox(comboBox, m_functionType);
- break;
- case FieldType::DataType:
- Serializer::fillComboBox(comboBox, m_returnType);
- break;
-
- default:
- break;
- }
-}
-
-bool GeneratedFunction::canHaveSubitems() const
-{
- return true;
-}
-
-QStringList GeneratedFunction::getCaptions() const
-{
- return QStringList() << QString("Function") << QString("%1 %2(...)").arg(Serializer::convertEnumToString(m_returnType), m_functionName);
-}
-
-GeneratedBase* GeneratedFunction::appendItem()
-{
- Q_ASSERT(canHaveSubitems());
-
- GeneratedBase* newItem = new GeneratedAction(this);
- addItem(newItem);
- return newItem;
-}
-
-GeneratedFunction::DataType GeneratedFunction::getReturnType() const
-{
- return m_returnType;
-}
-
-void GeneratedFunction::setReturnType(DataType returnType)
-{
- m_returnType = returnType;
-}
-
-GeneratedAction::GeneratedAction(QObject* parent) :
- BaseClass(parent),
- m_actionType(CreateObject)
-{
-
-}
-
-bool GeneratedAction::hasField(FieldType fieldType) const
-{
- switch (fieldType)
- {
- case FieldType::Name:
- return m_actionType == CreateObject;
- case FieldType::ItemType:
- return true;
- case FieldType::DataType:
- return hasField(FieldType::Name) && !m_variableName.isEmpty();
- case FieldType::Description:
- return m_actionType == Code;
-
- default:
- break;
- }
-
- return false;
-}
-
-QVariant GeneratedAction::readField(GeneratedBase::FieldType fieldType) const
-{
- switch (fieldType)
- {
- case FieldType::Name:
- return m_variableName;
- case FieldType::ItemType:
- return int(m_actionType);
- case FieldType::DataType:
- return int(m_variableType);
- case FieldType::Description:
- return m_code;
-
- default:
- break;
- }
-
- return QVariant();
-}
-
-void GeneratedAction::writeField(GeneratedBase::FieldType fieldType, QVariant value)
-{
- switch (fieldType)
- {
- case FieldType::Name:
- m_variableName = value.toString();
- break;
- case FieldType::ItemType:
- m_actionType = static_cast(value.toInt());
- break;
- case FieldType::DataType:
- m_variableType = static_cast(value.toInt());
- break;
- case FieldType::Description:
- m_code = value.toString();
- break;
-
- default:
- break;
- }
-}
-
-void GeneratedAction::fillComboBox(QComboBox* comboBox, FieldType fieldType)
-{
- switch (fieldType)
- {
- case FieldType::ItemType:
- Serializer::fillComboBox(comboBox, m_actionType);
- break;
- case FieldType::DataType:
- Serializer::fillComboBox(comboBox, m_variableType);
- break;
-
- default:
- break;
- }
-}
-
-bool GeneratedAction::canHaveSubitems() const
-{
- switch (m_actionType)
- {
- case Parameters:
- case CreateObject:
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-QStringList GeneratedAction::getCaptions() const
-{
- return QStringList() << QString("Action %1").arg(Serializer::convertEnumToString(m_actionType)) << (!m_variableName.isEmpty() ? QString("%1 %2").arg(Serializer::convertEnumToString(m_variableType), m_variableName) : QString());
-}
-
-GeneratedBase* GeneratedAction::appendItem()
-{
- Q_ASSERT(canHaveSubitems());
- GeneratedBase* newItem = nullptr;
- switch (m_actionType)
- {
- case Parameters:
- newItem = new GeneratedParameter(this);
- break;
-
- default:
- newItem = new GeneratedPDFObject(this);
- break;
- }
-
- addItem(newItem);
- return newItem;
-}
-
-GeneratedAction::ActionType GeneratedAction::getActionType() const
-{
- return m_actionType;
-}
-
-void GeneratedAction::setActionType(ActionType actionType)
-{
- m_actionType = actionType;
-
- if (!canHaveSubitems())
- {
- clearItems();
- }
-}
-
-QString GeneratedAction::getVariableName() const
-{
- return m_variableName;
-}
-
-void GeneratedAction::setVariableName(const QString& variableName)
-{
- m_variableName = variableName;
-}
-
-GeneratedAction::DataType GeneratedAction::getVariableType() const
-{
- return m_variableType;
-}
-
-void GeneratedAction::setVariableType(DataType variableType)
-{
- m_variableType = variableType;
-}
-
-QString GeneratedAction::getCode() const
-{
- return m_code;
-}
-
-void GeneratedAction::setCode(const QString& code)
-{
- m_code = code;
-}
-
-void GeneratedAction::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
-{
- if (pass == Pass::Enter && getActionType() == Code)
- {
- QString indent(parameters.indent, QChar(QChar::Space));
- QStringList lines = getCode().split(QChar('\n'), Qt::KeepEmptyParts, Qt::CaseInsensitive);
-
- for (QString string : lines)
- {
- string = string.trimmed();
- if (!string.isEmpty())
- {
- stream << indent << string << Qt::endl;
- }
- else
- {
- stream << Qt::endl;
- }
- }
- }
-
- if (pass == Pass::Leave && getActionType() == CreateObject)
- {
- QString indent(parameters.indent, QChar(QChar::Space));
-
- switch (getVariableType())
- {
- case _PDFObject:
- {
- stream << indent << getCppType(getVariableType()) << " " << getVariableName() << " = objectBuilder.takeObject();";
- break;
- }
-
- case _PDFObjectReference:
- {
- stream << indent << getCppType(getVariableType()) << " " << getVariableName() << " = addObject(objectBuilder.takeObject());";
- break;
- }
-
- default:
- Q_ASSERT(false);
- break;
- }
- }
-
- if (pass == Pass::Leave && getActionType() != Parameters && !parameters.isLastItem)
- {
- stream << Qt::endl;
- }
-}
-
-void GeneratedBase::generateSourceCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
-{
- generateSourceCodeImpl(stream, parameters, Pass::Enter);
-
- for (const QObject* object : m_items)
- {
- const GeneratedBase* generatedBase = qobject_cast(object);
- CodeGeneratorParameters parametersTemporary = parameters;
- parametersTemporary.isFirstItem = object == m_items.front();
- parametersTemporary.isLastItem = object == m_items.back();
- generatedBase->generateSourceCode(stream, parametersTemporary);
- }
-
- generateSourceCodeImpl(stream, parameters, Pass::Leave);
-}
-
-void GeneratedBase::applyFunctor(std::function& functor) const
-{
- functor(this, Pass::Enter);
-
- for (const QObject* object : m_items)
- {
- const GeneratedBase* generatedBase = qobject_cast(object);
- generatedBase->applyFunctor(functor);
- }
-
- functor(this, Pass::Leave);
-}
-
-bool GeneratedBase::canPerformOperation(Operation operation) const
-{
- const bool isFunction = qobject_cast(this) != nullptr;
- switch (operation)
- {
- case Operation::Delete:
- return !isFunction;
-
- case Operation::MoveUp:
- {
- if (const GeneratedBase* parentBase = getParent())
- {
- QObjectList items = parentBase->getItems();
- return items.indexOf(const_cast(this)) > 0;
- }
-
- break;
- }
-
- case Operation::MoveDown:
- {
- if (const GeneratedBase* parentBase = getParent())
- {
- QObjectList items = parentBase->getItems();
- return items.indexOf(const_cast(this)) < items.size() - 1;
- }
-
- break;
- }
-
- case Operation::NewSibling:
- return !isFunction;
-
- case Operation::NewChild:
- return canHaveSubitems();
-
- default:
- break;
- }
-
- return false;
-}
-
-void GeneratedBase::performOperation(GeneratedBase::Operation operation)
-{
- switch (operation)
- {
- case Operation::Delete:
- {
- getParent()->removeItem(this);
- break;
- }
-
- case Operation::MoveUp:
- {
- GeneratedBase* parentItem = getParent();
- QObjectList items = parentItem->getItems();
- const int index = items.indexOf(this);
- items.removeAll(const_cast(this));
- items.insert(index - 1, this);
- parentItem->setItems(qMove(items));
- break;
- }
-
- case Operation::MoveDown:
- {
- GeneratedBase* parentItem = getParent();
- QObjectList items = parentItem->getItems();
- const int index = items.indexOf(this);
- items.removeAll(const_cast(this));
- items.insert(index + 1, this);
- parentItem->setItems(qMove(items));
- break;
- }
-
- case Operation::NewSibling:
- {
- GeneratedBase* parentItem = getParent();
- if (GeneratedBase* createdItem = parentItem->appendItem())
- {
- QObjectList items = parentItem->getItems();
- items.removeAll(createdItem);
- items.insert(items.indexOf(const_cast(this)) + 1, createdItem);
- parentItem->setItems(qMove(items));
- }
- break;
- }
-
- case Operation::NewChild:
- {
- appendItem();
- break;
- }
-
- default:
- break;
- }
-}
-
-QObjectList GeneratedBase::getItems() const
-{
- return m_items;
-}
-
-void GeneratedBase::setItems(const QObjectList& items)
-{
- m_items = items;
-}
-
-void GeneratedBase::addItem(QObject* object)
-{
- object->setParent(this);
- m_items.append(object);
-}
-
-void GeneratedBase::removeItem(QObject* object)
-{
- object->deleteLater();
- m_items.removeAll(object);
-}
-
-void GeneratedBase::clearItems()
-{
- qDeleteAll(m_items);
- m_items.clear();
-}
-
-void GeneratedBase::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
-{
- Q_UNUSED(stream);
- Q_UNUSED(parameters);
- Q_UNUSED(pass);
-}
-
-QString GeneratedBase::getCppType(DataType type) const
-{
- return Serializer::convertEnumToString(type).mid(1);
-}
-
-QStringList GeneratedBase::getFormattedTextWithLayout(QString firstPrefix, QString prefix, QString text, int indent) const
-{
- QFont font = QApplication::font();
- QFontMetrics fontMetrics(font);
-
- int usedLength = indent + qMax(firstPrefix.length(), prefix.length());
- int length = 80 - usedLength;
- QString testText(length, QChar('A'));
- int width = fontMetrics.width(testText);
-
- QTextLayout layout(text, font);
- layout.setCacheEnabled(false);
- QTextOption textOption = layout.textOption();
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- layout.setTextOption(textOption);
-
- layout.beginLayout();
- while (true)
- {
- QTextLine textLine = layout.createLine();
- if (!textLine.isValid())
- {
- break;
- }
-
- textLine.setLineWidth(width);
- }
- layout.endLayout();
-
- QStringList texts;
- const int lineCount = layout.lineCount();
- for (int i = 0; i < lineCount; ++i)
- {
- QTextLine line = layout.lineAt(i);
- texts << text.mid(line.textStart(), line.textLength());
- }
- return getFormattedTextBlock(firstPrefix, prefix, texts, indent);
-}
-
-QStringList GeneratedBase::getFormattedTextBlock(QString firstPrefix, QString prefix, QStringList texts, int indent) const
-{
- QString indentText(indent, QChar(QChar::Space));
- firstPrefix.prepend(indentText);
- prefix.prepend(indentText);
-
- QStringList result;
- QString currentPrefix = firstPrefix;
- for (const QString& text : texts)
- {
- result << QString("%1%2").arg(currentPrefix, text);
- currentPrefix = prefix;
- }
- return result;
-}
-
-GeneratedPDFObject::GeneratedPDFObject(QObject* parent) :
- BaseClass(parent)
-{
-
-}
-
-bool GeneratedPDFObject::hasField(GeneratedBase::FieldType fieldType) const
-{
- switch (fieldType)
- {
- case FieldType::Name:
- return m_objectType == DictionaryItemSimple || m_objectType == DictionaryItemComplex;
- case FieldType::ItemType:
- return true;
- case FieldType::Value:
- return m_objectType == Object || m_objectType == ArraySimple || m_objectType == DictionaryItemSimple;
-
- default:
- break;
- }
-
- return false;
-}
-
-QVariant GeneratedPDFObject::readField(GeneratedBase::FieldType fieldType) const
-{
- switch (fieldType)
- {
- case FieldType::Name:
- return m_dictionaryItemName;
- case FieldType::ItemType:
- return int(m_objectType);
- case FieldType::Value:
- return m_value;
-
- default:
- break;
- }
-
- return QVariant();
-}
-
-void GeneratedPDFObject::writeField(GeneratedBase::FieldType fieldType, QVariant value)
-{
- switch (fieldType)
- {
- case FieldType::Name:
- m_dictionaryItemName = value.toString();
- break;
- case FieldType::ItemType:
- m_objectType = static_cast(value.toInt());
- break;
- case FieldType::Value:
- m_value = value.toString();
- break;
-
- default:
- break;
- }
-}
-
-void GeneratedPDFObject::fillComboBox(QComboBox* comboBox, GeneratedBase::FieldType fieldType)
-{
- switch (fieldType)
- {
- case FieldType::ItemType:
- Serializer::fillComboBox(comboBox, m_objectType);
- break;
-
- default:
- break;
- }
-}
-
-bool GeneratedPDFObject::canHaveSubitems() const
-{
- switch (m_objectType)
- {
- case ArrayComplex:
- case Dictionary:
- case DictionaryItemComplex:
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-QStringList GeneratedPDFObject::getCaptions() const
-{
- QString name;
- switch (m_objectType)
- {
- case Object:
- name = tr("Object");
- break;
- case ArraySimple:
- name = tr("Array (simple)");
- break;
- case ArrayComplex:
- name = tr("Array (complex)");
- break;
- case Dictionary:
- name = tr("Dictionary");
- break;
- case DictionaryItemSimple:
- name = tr("Item (simple), name = '%1'").arg(m_dictionaryItemName);
- break;
- case DictionaryItemComplex:
- name = tr("Item (complex), name = '%1'").arg(m_dictionaryItemName);
- break;
-
- default:
- Q_ASSERT(false);
- break;
- }
-
- return QStringList() << name << m_value;
-}
-
-GeneratedBase* GeneratedPDFObject::appendItem()
-{
- Q_ASSERT(canHaveSubitems());
- GeneratedBase* newItem = new GeneratedPDFObject(this);
- addItem(newItem);
- return newItem;
-}
-
-QString GeneratedPDFObject::getValue() const
-{
- return m_value;
-}
-
-void GeneratedPDFObject::setValue(const QString& value)
-{
- m_value = value;
-}
-
-GeneratedPDFObject::ObjectType GeneratedPDFObject::getObjectType() const
-{
- return m_objectType;
-}
-
-void GeneratedPDFObject::setObjectType(ObjectType objectType)
-{
- m_objectType = objectType;
-
- if (!canHaveSubitems())
- {
- clearItems();
- }
-}
-
-QString GeneratedPDFObject::getDictionaryItemName() const
-{
- return m_dictionaryItemName;
-}
-
-void GeneratedPDFObject::setDictionaryItemName(const QString& dictionaryItemName)
-{
- m_dictionaryItemName = dictionaryItemName;
-}
-
-void GeneratedPDFObject::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
-{
- QString indent(parameters.indent, QChar(QChar::Space));
- QString writeTo("objectBuilder << ");
-
- switch (getObjectType())
- {
- case codegen::GeneratedPDFObject::Object:
- {
- if (pass == Pass::Enter)
- {
- stream << indent << writeTo << getValue().trimmed() << ";" << Qt::endl;
- }
- break;
- }
-
- case codegen::GeneratedPDFObject::ArraySimple:
- {
- if (pass == Pass::Enter)
- {
- stream << indent << "objectBuilder.beginArray();" << Qt::endl;
- for (const QString& arrayPart : getValue().trimmed().split(";"))
- {
- stream << indent << writeTo << arrayPart << ";" << Qt::endl;
- }
- stream << indent << "objectBuilder.endArray();" << Qt::endl;
- }
- break;
- }
-
- case codegen::GeneratedPDFObject::ArrayComplex:
- {
- if (pass == Pass::Enter)
- {
- stream << indent << "objectBuilder.beginArray();" << Qt::endl;
- }
- if (pass == Pass::Leave)
- {
- stream << indent << "objectBuilder.endArray();" << Qt::endl;
- }
- break;
- }
-
- case codegen::GeneratedPDFObject::Dictionary:
- {
- if (pass == Pass::Enter)
- {
- stream << indent << "objectBuilder.beginDictionary();" << Qt::endl;
- }
- if (pass == Pass::Leave)
- {
- stream << indent << "objectBuilder.endDictionary();" << Qt::endl;
- }
- break;
- }
-
- case codegen::GeneratedPDFObject::DictionaryItemSimple:
- {
- if (pass == Pass::Enter)
- {
- stream << indent << QString("objectBuilder.beginDictionaryItem(\"%1\");").arg(getDictionaryItemName()) << Qt::endl;
- stream << indent << writeTo << getValue().trimmed() << ";" << Qt::endl;
- stream << indent << "objectBuilder.endDictionaryItem();" << Qt::endl;
- }
- break;
- }
-
- case codegen::GeneratedPDFObject::DictionaryItemComplex:
- {
- if (pass == Pass::Enter)
- {
- stream << indent << QString("objectBuilder.beginDictionaryItem(\"%1\");").arg(getDictionaryItemName()) << Qt::endl;
- }
- if (pass == Pass::Leave)
- {
- stream << indent << "objectBuilder.endDictionaryItem();" << Qt::endl;
- }
- break;
- }
-
- default:
- Q_ASSERT(false);
- break;
- }
-}
-
-GeneratedParameter::GeneratedParameter(QObject* parent) :
- BaseClass(parent)
-{
-
-}
-
-bool GeneratedParameter::hasField(GeneratedBase::FieldType fieldType) const
-{
- switch (fieldType)
- {
- case FieldType::Name:
- case FieldType::DataType:
- case FieldType::Description:
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-QVariant GeneratedParameter::readField(GeneratedBase::FieldType fieldType) const
-{
- switch (fieldType)
- {
- case FieldType::Name:
- return m_parameterName;
- case FieldType::DataType:
- return m_parameterDataType;
- case FieldType::Description:
- return m_parameterDescription;
-
- default:
- break;
- }
-
- return QVariant();
-}
-
-void GeneratedParameter::writeField(GeneratedBase::FieldType fieldType, QVariant value)
-{
- switch (fieldType)
- {
- case FieldType::Name:
- m_parameterName = value.toString();
- break;
- case FieldType::DataType:
- m_parameterDataType = static_cast(value.toInt());
- break;
- case FieldType::Description:
- m_parameterDescription = value.toString();
- break;
-
- default:
- break;
- }
-}
-
-void GeneratedParameter::fillComboBox(QComboBox* comboBox, GeneratedBase::FieldType fieldType)
-{
- switch (fieldType)
- {
- case FieldType::DataType:
- Serializer::fillComboBox(comboBox, m_parameterDataType);
- break;
-
- default:
- break;
- }
-}
-
-bool GeneratedParameter::canHaveSubitems() const
-{
- return false;
-}
-
-QStringList GeneratedParameter::getCaptions() const
-{
- return QStringList() << QString("%1 %2").arg(Serializer::convertEnumToString(m_parameterDataType)).arg(m_parameterName) << m_parameterDescription;
-}
-
-GeneratedBase* GeneratedParameter::appendItem()
-{
- return nullptr;
-}
-
-QString GeneratedParameter::getParameterName() const
-{
- return m_parameterName;
-}
-
-void GeneratedParameter::setParameterName(const QString& parameterName)
-{
- m_parameterName = parameterName;
-}
-
-GeneratedParameter::DataType GeneratedParameter::getParameterDataType() const
-{
- return m_parameterDataType;
-}
-
-void GeneratedParameter::setParameterDataType(const DataType& parameterDataType)
-{
- m_parameterDataType = parameterDataType;
-}
-
-QString GeneratedParameter::getParameterDescription() const
-{
- return m_parameterDescription;
-}
-
-void GeneratedParameter::setParameterDescription(const QString& parameterDescription)
-{
- m_parameterDescription = parameterDescription;
-}
-
-}
+// Copyright (C) 2020-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 .
+
+#include "codegenerator.h"
+
+#include
+#include
+#include
+#include
+#include
+
+namespace codegen
+{
+
+GeneratedCodeStorage::GeneratedCodeStorage(QObject* parent) :
+ BaseClass(parent)
+{
+
+}
+
+QObjectList GeneratedCodeStorage::getFunctions() const
+{
+ return m_functions;
+}
+
+void GeneratedCodeStorage::setFunctions(const QObjectList& functions)
+{
+ m_functions = functions;
+
+ auto comparator = [](const QObject* left, const QObject* right)
+ {
+ const GeneratedFunction* leftFunction = qobject_cast(left);
+ const GeneratedFunction* rightFunction = qobject_cast(right);
+ return leftFunction->getFunctionName() < rightFunction->getFunctionName();
+ };
+ std::sort(m_functions.begin(), m_functions.end(), comparator);
+}
+
+GeneratedFunction* GeneratedCodeStorage::addFunction(const QString& name)
+{
+ GeneratedFunction* function = new GeneratedFunction(this);
+ function->setFunctionName(name);
+ m_functions.append(function);
+ return function;
+}
+
+GeneratedFunction* GeneratedCodeStorage::addFunction(GeneratedFunction* function)
+{
+ function->setParent(this);
+ m_functions.append(function);
+ return function;
+}
+
+void GeneratedCodeStorage::removeFunction(GeneratedFunction* function)
+{
+ function->deleteLater();
+ m_functions.removeOne(function);
+}
+
+void GeneratedCodeStorage::generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
+{
+ stream << Qt::endl << Qt::endl;
+
+ for (const QObject* object : m_functions)
+ {
+ const GeneratedFunction* generatedFunction = qobject_cast(object);
+ generatedFunction->generateCode(stream, parameters);
+ stream << Qt::endl << Qt::endl;
+ }
+}
+
+QObject* Serializer::load(const QDomElement& element, QObject* parent)
+{
+ QString className = element.attribute("class");
+ const int metaTypeId = QMetaType::type(className.toLatin1());
+ const QMetaObject* metaObject = QMetaType::metaObjectForType(metaTypeId);
+
+ if (metaObject)
+ {
+ QObject* deserializedObject = metaObject->newInstance(Q_ARG(QObject*, parent));
+
+ const int propertyCount = metaObject->propertyCount();
+ for (int i = 0; i < propertyCount; ++i)
+ {
+ QMetaProperty property = metaObject->property(i);
+ if (property.isWritable())
+ {
+ // Find, if property was serialized
+ QDomElement propertyElement;
+ QDomNodeList children = element.childNodes();
+ for (int i = 0; i < children.count(); ++i)
+ {
+ QDomNode child = children.item(i);
+ if (child.isElement())
+ {
+ QDomElement childElement = child.toElement();
+ QString attributeName = childElement.attribute("name");
+ if (attributeName == property.name())
+ {
+ propertyElement = child.toElement();
+ break;
+ }
+ }
+ }
+
+ if (!propertyElement.isNull())
+ {
+ // Deserialize the element
+ if (property.isEnumType())
+ {
+ QMetaEnum metaEnum = property.enumerator();
+ Q_ASSERT(metaEnum.isValid());
+ property.write(deserializedObject, metaEnum.keyToValue(propertyElement.text().toLatin1().data()));
+ }
+ else if (property.userType() == qMetaTypeId())
+ {
+ QObjectList objectList;
+ QDomNodeList children = propertyElement.childNodes();
+ for (int i = 0; i < children.count(); ++i)
+ {
+ QDomNode node = children.item(i);
+ if (node.isElement())
+ {
+ QDomElement element = node.toElement();
+ if (QObject* object = Serializer::load(element, deserializedObject))
+ {
+ objectList.append(object);
+ }
+ }
+ }
+
+ property.write(deserializedObject, QVariant::fromValue(qMove(objectList)));
+ }
+ else
+ {
+ QVariant value = propertyElement.text();
+ property.write(deserializedObject, value);
+ }
+ }
+ }
+ }
+
+ return deserializedObject;
+ }
+
+ return nullptr;
+}
+
+void Serializer::store(QObject* object, QDomElement& element)
+{
+ Q_ASSERT(object);
+
+ const QMetaObject* metaObject = object->metaObject();
+ element.setAttribute("class", QString(metaObject->className()));
+
+ const int propertyCount = metaObject->propertyCount();
+ if (propertyCount > 0)
+ {
+ for (int i = 0; i < propertyCount; ++i)
+ {
+ QMetaProperty property = metaObject->property(i);
+ if (property.isReadable())
+ {
+ QDomElement propertyElement = element.ownerDocument().createElement("property");
+ element.appendChild(propertyElement);
+ propertyElement.setAttribute("name", property.name());
+
+ QVariant value = property.read(object);
+ if (property.isEnumType())
+ {
+ QMetaEnum metaEnum = property.enumerator();
+ Q_ASSERT(metaEnum.isValid());
+ propertyElement.appendChild(propertyElement.ownerDocument().createTextNode(metaEnum.valueToKey(value.toInt())));
+ }
+ else if (value.canConvert())
+ {
+ QObjectList objectList = value.value();
+ for (QObject* currentObject : objectList)
+ {
+ QDomElement objectElement = element.ownerDocument().createElement("QObject");
+ propertyElement.appendChild(objectElement);
+ Serializer::store(currentObject, objectElement);
+ }
+ }
+ else
+ {
+ propertyElement.appendChild(propertyElement.ownerDocument().createTextNode(value.toString()));
+ }
+ }
+ }
+ }
+}
+
+QObject* Serializer::clone(QObject* object, QObject* parent)
+{
+ QDomDocument document;
+ QDomElement rootElement = document.createElement("root");
+ document.appendChild(rootElement);
+ Serializer::store(object, rootElement);
+ return Serializer::load(rootElement, parent);
+}
+
+CodeGenerator::CodeGenerator(QObject* parent) :
+ BaseClass(parent)
+{
+ qRegisterMetaType("codegen::GeneratedCodeStorage");
+ qRegisterMetaType("codegen::GeneratedFunction");
+ qRegisterMetaType("codegen::GeneratedBase");
+ qRegisterMetaType("codegen::GeneratedParameter");
+ qRegisterMetaType("codegen::GeneratedPDFObject");
+ qRegisterMetaType("codegen::GeneratedAction");
+ qRegisterMetaType("QObjectList");
+}
+
+void CodeGenerator::initialize()
+{
+ m_storage = new GeneratedCodeStorage(this);
+}
+
+void CodeGenerator::load(const QDomDocument& document)
+{
+ delete m_storage;
+ m_storage = nullptr;
+
+ m_storage = qobject_cast(Serializer::load(document.firstChildElement("root"), this));
+}
+
+void CodeGenerator::store(QDomDocument& document)
+{
+ if (m_storage)
+ {
+ QDomElement rootElement = document.createElement("root");
+ document.appendChild(rootElement);
+ Serializer::store(m_storage, rootElement);
+ }
+}
+
+void CodeGenerator::generateCode(QString headerName, QString sourceName) const
+{
+ QString startMark = "/* START GENERATED CODE */";
+ QString endMark = "/* END GENERATED CODE */";
+ QString className = "PDFDocumentBuilder";
+ const int indent = 4;
+
+ QFile headerFile(headerName);
+ if (headerFile.exists())
+ {
+ if (headerFile.open(QFile::ReadOnly | QFile::Text))
+ {
+ QString utfCode = QString::fromUtf8(headerFile.readAll());
+ headerFile.close();
+
+ int startIndex = utfCode.indexOf(startMark, Qt::CaseSensitive) + startMark.length();
+ int endIndex = utfCode.indexOf(endMark, Qt::CaseSensitive);
+
+ QString frontPart = utfCode.left(startIndex);
+ QString backPart = utfCode.mid(endIndex);
+ QString headerGeneratedCode = generateHeader(indent);
+ QString allCode = frontPart + headerGeneratedCode + backPart;
+
+ headerFile.open(QFile::WriteOnly | QFile::Truncate);
+ headerFile.write(allCode.toUtf8());
+ headerFile.close();
+ }
+ }
+
+ QFile sourceFile(sourceName);
+ if (sourceFile.exists())
+ {
+ if (sourceFile.open(QFile::ReadOnly | QFile::Text))
+ {
+ QString utfCode = QString::fromUtf8(sourceFile.readAll());
+ sourceFile.close();
+
+ int startIndex = utfCode.indexOf(startMark, Qt::CaseSensitive) + startMark.length();
+ int endIndex = utfCode.indexOf(endMark, Qt::CaseSensitive);
+
+ QString frontPart = utfCode.left(startIndex);
+ QString backPart = utfCode.mid(endIndex);
+ QString sourceGeneratedCode = generateSource(className, indent);
+ QString allCode = frontPart + sourceGeneratedCode + backPart;
+
+ sourceFile.open(QFile::WriteOnly | QFile::Truncate);
+ sourceFile.write(allCode.toUtf8());
+ sourceFile.close();
+ }
+ }
+}
+
+QString CodeGenerator::generateHeader(int indent) const
+{
+ QByteArray ba;
+ {
+ QTextStream stream(&ba, QIODevice::WriteOnly);
+ stream.setCodec("UTF-8");
+ stream.setRealNumberPrecision(3);
+ stream.setRealNumberNotation(QTextStream::FixedNotation);
+
+ CodeGeneratorParameters parameters;
+ parameters.header = true;
+ parameters.indent = indent;
+ m_storage->generateCode(stream, parameters);
+ }
+
+ return QString::fromUtf8(ba);
+}
+
+QString CodeGenerator::generateSource(QString className, int indent) const
+{
+ QByteArray ba;
+ {
+ QTextStream stream(&ba, QIODevice::WriteOnly);
+ stream.setCodec("UTF-8");
+ stream.setRealNumberPrecision(3);
+ stream.setRealNumberNotation(QTextStream::FixedNotation);
+
+ CodeGeneratorParameters parameters;
+ parameters.header = false;
+ parameters.indent = indent;
+ parameters.className = className;
+ m_storage->generateCode(stream, parameters);
+ }
+
+ return QString::fromUtf8(ba);
+}
+
+GeneratedFunction::GeneratedFunction(QObject* parent) :
+ BaseClass(parent)
+{
+
+}
+
+QString GeneratedFunction::getFunctionTypeString() const
+{
+ return Serializer::convertEnumToString(m_functionType);
+}
+
+void GeneratedFunction::setFunctionTypeString(const QString& string)
+{
+ Serializer::convertStringToEnum(string, m_functionType);
+}
+
+GeneratedFunction::FunctionType GeneratedFunction::getFunctionType() const
+{
+ return m_functionType;
+}
+
+void GeneratedFunction::setFunctionType(const FunctionType& functionType)
+{
+ m_functionType = functionType;
+}
+
+QString GeneratedFunction::getFunctionName() const
+{
+ return m_functionName;
+}
+
+void GeneratedFunction::setFunctionName(const QString& functionName)
+{
+ m_functionName = functionName;
+}
+
+QString GeneratedFunction::getFunctionDescription() const
+{
+ return m_functionDescription;
+}
+
+void GeneratedFunction::setFunctionDescription(const QString& functionDescription)
+{
+ m_functionDescription = functionDescription;
+}
+
+GeneratedFunction* GeneratedFunction::clone(QObject* parent)
+{
+ return qobject_cast(Serializer::clone(this, parent));
+}
+
+void GeneratedFunction::generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
+{
+ QStringList parameterCaptions;
+ QStringList parameterTexts;
+ std::function gatherParameters = [&](const GeneratedBase* object, Pass pass)
+ {
+ if (pass != Pass::Enter)
+ {
+ return;
+ }
+
+ if (const GeneratedParameter* generatedParameter = qobject_cast(object))
+ {
+ parameterCaptions << QString("%1 %2").arg(generatedParameter->getParameterName(), generatedParameter->getParameterDescription());
+ parameterTexts << QString("%1 %2").arg(getCppType(generatedParameter->getParameterDataType()), generatedParameter->getParameterName());
+ }
+ };
+ applyFunctor(gatherParameters);
+
+ if (parameterTexts.isEmpty())
+ {
+ parameterTexts << "";
+ }
+
+ if (parameters.header)
+ {
+ // Generate header source code
+
+ // Function comments
+ for (const QString& string : getFormattedTextWithLayout("/// ", "/// ", getFunctionDescription(), parameters.indent))
+ {
+ stream << string << Qt::endl;
+ }
+
+ // Function parameter comments
+ for (const QString& parameterCaption : parameterCaptions)
+ {
+ for (const QString& string : getFormattedTextWithLayout("/// \\param ", "/// ", parameterCaption, parameters.indent))
+ {
+ stream << string << Qt::endl;
+ }
+ }
+
+ // Function declaration
+ QString functionHeader = QString("%1 %2(").arg(getCppType(getReturnType()), getFunctionName());
+ QString functionHeaderNext(functionHeader.length(), QChar(QChar::Space));
+ QString functionFooter = QString(");");
+
+ for (QString& str : parameterTexts)
+ {
+ str += ",";
+ }
+ parameterTexts.back().replace(",", functionFooter);
+
+ QStringList functionDeclaration = getFormattedTextBlock(functionHeader, functionHeaderNext, parameterTexts, parameters.indent);
+ for (const QString& functionDeclarationItem : functionDeclaration)
+ {
+ stream << functionDeclarationItem << Qt::endl;
+ }
+ }
+ else
+ {
+ // Generate c++ source code
+ QString functionHeader = QString("%1 %2::%3(").arg(getCppType(getReturnType()), parameters.className, getFunctionName());
+ QString functionHeaderNext(functionHeader.length(), QChar(QChar::Space));
+ QString functionFooter = QString(")");
+
+ for (QString& str : parameterTexts)
+ {
+ str += ",";
+ }
+ parameterTexts.back().replace(",", functionFooter);
+
+ QStringList functionDeclaration = getFormattedTextBlock(functionHeader, functionHeaderNext, parameterTexts, 0);
+ for (const QString& functionDeclarationItem : functionDeclaration)
+ {
+ stream << functionDeclarationItem << Qt::endl;
+ }
+
+ QString indent(parameters.indent, QChar(QChar::Space));
+
+ stream << "{" << Qt::endl;
+ stream << indent << "PDFObjectFactory objectBuilder;" << Qt::endl << Qt::endl;
+
+ generateSourceCode(stream, parameters);
+
+ stream << "}" << Qt::endl;
+ }
+}
+
+bool GeneratedFunction::hasField(GeneratedBase::FieldType fieldType) const
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ case FieldType::ItemType:
+ case FieldType::DataType:
+ case FieldType::Description:
+ return true;
+
+ case FieldType::Value:
+ return false;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QVariant GeneratedFunction::readField(GeneratedBase::FieldType fieldType) const
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ return m_functionName;
+ case FieldType::ItemType:
+ return int(m_functionType);
+ case FieldType::DataType:
+ return int(m_returnType);
+ case FieldType::Description:
+ return m_functionDescription;
+
+ case FieldType::Value:
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+void GeneratedFunction::writeField(GeneratedBase::FieldType fieldType, QVariant value)
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ m_functionName = value.toString();
+ break;
+ case FieldType::ItemType:
+ m_functionType = static_cast(value.toInt());
+ break;
+ case FieldType::DataType:
+ m_returnType = static_cast(value.toInt());
+ break;
+ case FieldType::Description:
+ m_functionDescription = value.toString();
+ break;
+
+ case FieldType::Value:
+ default:
+ break;
+ }
+}
+
+void GeneratedFunction::fillComboBox(QComboBox* comboBox, GeneratedBase::FieldType fieldType)
+{
+ switch (fieldType)
+ {
+ case FieldType::ItemType:
+ Serializer::fillComboBox(comboBox, m_functionType);
+ break;
+ case FieldType::DataType:
+ Serializer::fillComboBox(comboBox, m_returnType);
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool GeneratedFunction::canHaveSubitems() const
+{
+ return true;
+}
+
+QStringList GeneratedFunction::getCaptions() const
+{
+ return QStringList() << QString("Function") << QString("%1 %2(...)").arg(Serializer::convertEnumToString(m_returnType), m_functionName);
+}
+
+GeneratedBase* GeneratedFunction::appendItem()
+{
+ Q_ASSERT(canHaveSubitems());
+
+ GeneratedBase* newItem = new GeneratedAction(this);
+ addItem(newItem);
+ return newItem;
+}
+
+GeneratedFunction::DataType GeneratedFunction::getReturnType() const
+{
+ return m_returnType;
+}
+
+void GeneratedFunction::setReturnType(DataType returnType)
+{
+ m_returnType = returnType;
+}
+
+GeneratedAction::GeneratedAction(QObject* parent) :
+ BaseClass(parent),
+ m_actionType(CreateObject)
+{
+
+}
+
+bool GeneratedAction::hasField(FieldType fieldType) const
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ return m_actionType == CreateObject;
+ case FieldType::ItemType:
+ return true;
+ case FieldType::DataType:
+ return hasField(FieldType::Name) && !m_variableName.isEmpty();
+ case FieldType::Description:
+ return m_actionType == Code;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QVariant GeneratedAction::readField(GeneratedBase::FieldType fieldType) const
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ return m_variableName;
+ case FieldType::ItemType:
+ return int(m_actionType);
+ case FieldType::DataType:
+ return int(m_variableType);
+ case FieldType::Description:
+ return m_code;
+
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+void GeneratedAction::writeField(GeneratedBase::FieldType fieldType, QVariant value)
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ m_variableName = value.toString();
+ break;
+ case FieldType::ItemType:
+ m_actionType = static_cast(value.toInt());
+ break;
+ case FieldType::DataType:
+ m_variableType = static_cast(value.toInt());
+ break;
+ case FieldType::Description:
+ m_code = value.toString();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void GeneratedAction::fillComboBox(QComboBox* comboBox, FieldType fieldType)
+{
+ switch (fieldType)
+ {
+ case FieldType::ItemType:
+ Serializer::fillComboBox(comboBox, m_actionType);
+ break;
+ case FieldType::DataType:
+ Serializer::fillComboBox(comboBox, m_variableType);
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool GeneratedAction::canHaveSubitems() const
+{
+ switch (m_actionType)
+ {
+ case Parameters:
+ case CreateObject:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QStringList GeneratedAction::getCaptions() const
+{
+ return QStringList() << QString("Action %1").arg(Serializer::convertEnumToString(m_actionType)) << (!m_variableName.isEmpty() ? QString("%1 %2").arg(Serializer::convertEnumToString(m_variableType), m_variableName) : QString());
+}
+
+GeneratedBase* GeneratedAction::appendItem()
+{
+ Q_ASSERT(canHaveSubitems());
+ GeneratedBase* newItem = nullptr;
+ switch (m_actionType)
+ {
+ case Parameters:
+ newItem = new GeneratedParameter(this);
+ break;
+
+ default:
+ newItem = new GeneratedPDFObject(this);
+ break;
+ }
+
+ addItem(newItem);
+ return newItem;
+}
+
+GeneratedAction::ActionType GeneratedAction::getActionType() const
+{
+ return m_actionType;
+}
+
+void GeneratedAction::setActionType(ActionType actionType)
+{
+ m_actionType = actionType;
+
+ if (!canHaveSubitems())
+ {
+ clearItems();
+ }
+}
+
+QString GeneratedAction::getVariableName() const
+{
+ return m_variableName;
+}
+
+void GeneratedAction::setVariableName(const QString& variableName)
+{
+ m_variableName = variableName;
+}
+
+GeneratedAction::DataType GeneratedAction::getVariableType() const
+{
+ return m_variableType;
+}
+
+void GeneratedAction::setVariableType(DataType variableType)
+{
+ m_variableType = variableType;
+}
+
+QString GeneratedAction::getCode() const
+{
+ return m_code;
+}
+
+void GeneratedAction::setCode(const QString& code)
+{
+ m_code = code;
+}
+
+void GeneratedAction::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
+{
+ if (pass == Pass::Enter && getActionType() == Code)
+ {
+ QString indent(parameters.indent, QChar(QChar::Space));
+ QStringList lines = getCode().split(QChar('\n'), Qt::KeepEmptyParts, Qt::CaseInsensitive);
+
+ for (QString string : lines)
+ {
+ string = string.trimmed();
+ if (!string.isEmpty())
+ {
+ stream << indent << string << Qt::endl;
+ }
+ else
+ {
+ stream << Qt::endl;
+ }
+ }
+ }
+
+ if (pass == Pass::Leave && getActionType() == CreateObject)
+ {
+ QString indent(parameters.indent, QChar(QChar::Space));
+
+ switch (getVariableType())
+ {
+ case _PDFObject:
+ {
+ stream << indent << getCppType(getVariableType()) << " " << getVariableName() << " = objectBuilder.takeObject();";
+ break;
+ }
+
+ case _PDFObjectReference:
+ {
+ stream << indent << getCppType(getVariableType()) << " " << getVariableName() << " = addObject(objectBuilder.takeObject());";
+ break;
+ }
+
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+ }
+
+ if (pass == Pass::Leave && getActionType() != Parameters && !parameters.isLastItem)
+ {
+ stream << Qt::endl;
+ }
+}
+
+void GeneratedBase::generateSourceCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
+{
+ generateSourceCodeImpl(stream, parameters, Pass::Enter);
+
+ for (const QObject* object : m_items)
+ {
+ const GeneratedBase* generatedBase = qobject_cast(object);
+ CodeGeneratorParameters parametersTemporary = parameters;
+ parametersTemporary.isFirstItem = object == m_items.front();
+ parametersTemporary.isLastItem = object == m_items.back();
+ generatedBase->generateSourceCode(stream, parametersTemporary);
+ }
+
+ generateSourceCodeImpl(stream, parameters, Pass::Leave);
+}
+
+void GeneratedBase::applyFunctor(std::function& functor) const
+{
+ functor(this, Pass::Enter);
+
+ for (const QObject* object : m_items)
+ {
+ const GeneratedBase* generatedBase = qobject_cast(object);
+ generatedBase->applyFunctor(functor);
+ }
+
+ functor(this, Pass::Leave);
+}
+
+bool GeneratedBase::canPerformOperation(Operation operation) const
+{
+ const bool isFunction = qobject_cast(this) != nullptr;
+ switch (operation)
+ {
+ case Operation::Delete:
+ return !isFunction;
+
+ case Operation::MoveUp:
+ {
+ if (const GeneratedBase* parentBase = getParent())
+ {
+ QObjectList items = parentBase->getItems();
+ return items.indexOf(const_cast(this)) > 0;
+ }
+
+ break;
+ }
+
+ case Operation::MoveDown:
+ {
+ if (const GeneratedBase* parentBase = getParent())
+ {
+ QObjectList items = parentBase->getItems();
+ return items.indexOf(const_cast(this)) < items.size() - 1;
+ }
+
+ break;
+ }
+
+ case Operation::NewSibling:
+ return !isFunction;
+
+ case Operation::NewChild:
+ return canHaveSubitems();
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void GeneratedBase::performOperation(GeneratedBase::Operation operation)
+{
+ switch (operation)
+ {
+ case Operation::Delete:
+ {
+ getParent()->removeItem(this);
+ break;
+ }
+
+ case Operation::MoveUp:
+ {
+ GeneratedBase* parentItem = getParent();
+ QObjectList items = parentItem->getItems();
+ const int index = items.indexOf(this);
+ items.removeAll(const_cast(this));
+ items.insert(index - 1, this);
+ parentItem->setItems(qMove(items));
+ break;
+ }
+
+ case Operation::MoveDown:
+ {
+ GeneratedBase* parentItem = getParent();
+ QObjectList items = parentItem->getItems();
+ const int index = items.indexOf(this);
+ items.removeAll(const_cast(this));
+ items.insert(index + 1, this);
+ parentItem->setItems(qMove(items));
+ break;
+ }
+
+ case Operation::NewSibling:
+ {
+ GeneratedBase* parentItem = getParent();
+ if (GeneratedBase* createdItem = parentItem->appendItem())
+ {
+ QObjectList items = parentItem->getItems();
+ items.removeAll(createdItem);
+ items.insert(items.indexOf(const_cast(this)) + 1, createdItem);
+ parentItem->setItems(qMove(items));
+ }
+ break;
+ }
+
+ case Operation::NewChild:
+ {
+ appendItem();
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+QObjectList GeneratedBase::getItems() const
+{
+ return m_items;
+}
+
+void GeneratedBase::setItems(const QObjectList& items)
+{
+ m_items = items;
+}
+
+void GeneratedBase::addItem(QObject* object)
+{
+ object->setParent(this);
+ m_items.append(object);
+}
+
+void GeneratedBase::removeItem(QObject* object)
+{
+ object->deleteLater();
+ m_items.removeAll(object);
+}
+
+void GeneratedBase::clearItems()
+{
+ qDeleteAll(m_items);
+ m_items.clear();
+}
+
+void GeneratedBase::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
+{
+ Q_UNUSED(stream);
+ Q_UNUSED(parameters);
+ Q_UNUSED(pass);
+}
+
+QString GeneratedBase::getCppType(DataType type) const
+{
+ return Serializer::convertEnumToString(type).mid(1);
+}
+
+QStringList GeneratedBase::getFormattedTextWithLayout(QString firstPrefix, QString prefix, QString text, int indent) const
+{
+ QFont font = QApplication::font();
+ QFontMetrics fontMetrics(font);
+
+ int usedLength = indent + qMax(firstPrefix.length(), prefix.length());
+ int length = 80 - usedLength;
+ QString testText(length, QChar('A'));
+ int width = fontMetrics.width(testText);
+
+ QTextLayout layout(text, font);
+ layout.setCacheEnabled(false);
+ QTextOption textOption = layout.textOption();
+ textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ layout.setTextOption(textOption);
+
+ layout.beginLayout();
+ while (true)
+ {
+ QTextLine textLine = layout.createLine();
+ if (!textLine.isValid())
+ {
+ break;
+ }
+
+ textLine.setLineWidth(width);
+ }
+ layout.endLayout();
+
+ QStringList texts;
+ const int lineCount = layout.lineCount();
+ for (int i = 0; i < lineCount; ++i)
+ {
+ QTextLine line = layout.lineAt(i);
+ texts << text.mid(line.textStart(), line.textLength());
+ }
+ return getFormattedTextBlock(firstPrefix, prefix, texts, indent);
+}
+
+QStringList GeneratedBase::getFormattedTextBlock(QString firstPrefix, QString prefix, QStringList texts, int indent) const
+{
+ QString indentText(indent, QChar(QChar::Space));
+ firstPrefix.prepend(indentText);
+ prefix.prepend(indentText);
+
+ QStringList result;
+ QString currentPrefix = firstPrefix;
+ for (const QString& text : texts)
+ {
+ result << QString("%1%2").arg(currentPrefix, text);
+ currentPrefix = prefix;
+ }
+ return result;
+}
+
+GeneratedPDFObject::GeneratedPDFObject(QObject* parent) :
+ BaseClass(parent)
+{
+
+}
+
+bool GeneratedPDFObject::hasField(GeneratedBase::FieldType fieldType) const
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ return m_objectType == DictionaryItemSimple || m_objectType == DictionaryItemComplex;
+ case FieldType::ItemType:
+ return true;
+ case FieldType::Value:
+ return m_objectType == Object || m_objectType == ArraySimple || m_objectType == DictionaryItemSimple;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QVariant GeneratedPDFObject::readField(GeneratedBase::FieldType fieldType) const
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ return m_dictionaryItemName;
+ case FieldType::ItemType:
+ return int(m_objectType);
+ case FieldType::Value:
+ return m_value;
+
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+void GeneratedPDFObject::writeField(GeneratedBase::FieldType fieldType, QVariant value)
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ m_dictionaryItemName = value.toString();
+ break;
+ case FieldType::ItemType:
+ m_objectType = static_cast(value.toInt());
+ break;
+ case FieldType::Value:
+ m_value = value.toString();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void GeneratedPDFObject::fillComboBox(QComboBox* comboBox, GeneratedBase::FieldType fieldType)
+{
+ switch (fieldType)
+ {
+ case FieldType::ItemType:
+ Serializer::fillComboBox(comboBox, m_objectType);
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool GeneratedPDFObject::canHaveSubitems() const
+{
+ switch (m_objectType)
+ {
+ case ArrayComplex:
+ case Dictionary:
+ case DictionaryItemComplex:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QStringList GeneratedPDFObject::getCaptions() const
+{
+ QString name;
+ switch (m_objectType)
+ {
+ case Object:
+ name = tr("Object");
+ break;
+ case ArraySimple:
+ name = tr("Array (simple)");
+ break;
+ case ArrayComplex:
+ name = tr("Array (complex)");
+ break;
+ case Dictionary:
+ name = tr("Dictionary");
+ break;
+ case DictionaryItemSimple:
+ name = tr("Item (simple), name = '%1'").arg(m_dictionaryItemName);
+ break;
+ case DictionaryItemComplex:
+ name = tr("Item (complex), name = '%1'").arg(m_dictionaryItemName);
+ break;
+
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ return QStringList() << name << m_value;
+}
+
+GeneratedBase* GeneratedPDFObject::appendItem()
+{
+ Q_ASSERT(canHaveSubitems());
+ GeneratedBase* newItem = new GeneratedPDFObject(this);
+ addItem(newItem);
+ return newItem;
+}
+
+QString GeneratedPDFObject::getValue() const
+{
+ return m_value;
+}
+
+void GeneratedPDFObject::setValue(const QString& value)
+{
+ m_value = value;
+}
+
+GeneratedPDFObject::ObjectType GeneratedPDFObject::getObjectType() const
+{
+ return m_objectType;
+}
+
+void GeneratedPDFObject::setObjectType(ObjectType objectType)
+{
+ m_objectType = objectType;
+
+ if (!canHaveSubitems())
+ {
+ clearItems();
+ }
+}
+
+QString GeneratedPDFObject::getDictionaryItemName() const
+{
+ return m_dictionaryItemName;
+}
+
+void GeneratedPDFObject::setDictionaryItemName(const QString& dictionaryItemName)
+{
+ m_dictionaryItemName = dictionaryItemName;
+}
+
+void GeneratedPDFObject::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
+{
+ QString indent(parameters.indent, QChar(QChar::Space));
+ QString writeTo("objectBuilder << ");
+
+ switch (getObjectType())
+ {
+ case codegen::GeneratedPDFObject::Object:
+ {
+ if (pass == Pass::Enter)
+ {
+ stream << indent << writeTo << getValue().trimmed() << ";" << Qt::endl;
+ }
+ break;
+ }
+
+ case codegen::GeneratedPDFObject::ArraySimple:
+ {
+ if (pass == Pass::Enter)
+ {
+ stream << indent << "objectBuilder.beginArray();" << Qt::endl;
+ for (const QString& arrayPart : getValue().trimmed().split(";"))
+ {
+ stream << indent << writeTo << arrayPart << ";" << Qt::endl;
+ }
+ stream << indent << "objectBuilder.endArray();" << Qt::endl;
+ }
+ break;
+ }
+
+ case codegen::GeneratedPDFObject::ArrayComplex:
+ {
+ if (pass == Pass::Enter)
+ {
+ stream << indent << "objectBuilder.beginArray();" << Qt::endl;
+ }
+ if (pass == Pass::Leave)
+ {
+ stream << indent << "objectBuilder.endArray();" << Qt::endl;
+ }
+ break;
+ }
+
+ case codegen::GeneratedPDFObject::Dictionary:
+ {
+ if (pass == Pass::Enter)
+ {
+ stream << indent << "objectBuilder.beginDictionary();" << Qt::endl;
+ }
+ if (pass == Pass::Leave)
+ {
+ stream << indent << "objectBuilder.endDictionary();" << Qt::endl;
+ }
+ break;
+ }
+
+ case codegen::GeneratedPDFObject::DictionaryItemSimple:
+ {
+ if (pass == Pass::Enter)
+ {
+ stream << indent << QString("objectBuilder.beginDictionaryItem(\"%1\");").arg(getDictionaryItemName()) << Qt::endl;
+ stream << indent << writeTo << getValue().trimmed() << ";" << Qt::endl;
+ stream << indent << "objectBuilder.endDictionaryItem();" << Qt::endl;
+ }
+ break;
+ }
+
+ case codegen::GeneratedPDFObject::DictionaryItemComplex:
+ {
+ if (pass == Pass::Enter)
+ {
+ stream << indent << QString("objectBuilder.beginDictionaryItem(\"%1\");").arg(getDictionaryItemName()) << Qt::endl;
+ }
+ if (pass == Pass::Leave)
+ {
+ stream << indent << "objectBuilder.endDictionaryItem();" << Qt::endl;
+ }
+ break;
+ }
+
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+}
+
+GeneratedParameter::GeneratedParameter(QObject* parent) :
+ BaseClass(parent)
+{
+
+}
+
+bool GeneratedParameter::hasField(GeneratedBase::FieldType fieldType) const
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ case FieldType::DataType:
+ case FieldType::Description:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QVariant GeneratedParameter::readField(GeneratedBase::FieldType fieldType) const
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ return m_parameterName;
+ case FieldType::DataType:
+ return m_parameterDataType;
+ case FieldType::Description:
+ return m_parameterDescription;
+
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+void GeneratedParameter::writeField(GeneratedBase::FieldType fieldType, QVariant value)
+{
+ switch (fieldType)
+ {
+ case FieldType::Name:
+ m_parameterName = value.toString();
+ break;
+ case FieldType::DataType:
+ m_parameterDataType = static_cast(value.toInt());
+ break;
+ case FieldType::Description:
+ m_parameterDescription = value.toString();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void GeneratedParameter::fillComboBox(QComboBox* comboBox, GeneratedBase::FieldType fieldType)
+{
+ switch (fieldType)
+ {
+ case FieldType::DataType:
+ Serializer::fillComboBox(comboBox, m_parameterDataType);
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool GeneratedParameter::canHaveSubitems() const
+{
+ return false;
+}
+
+QStringList GeneratedParameter::getCaptions() const
+{
+ return QStringList() << QString("%1 %2").arg(Serializer::convertEnumToString(m_parameterDataType)).arg(m_parameterName) << m_parameterDescription;
+}
+
+GeneratedBase* GeneratedParameter::appendItem()
+{
+ return nullptr;
+}
+
+QString GeneratedParameter::getParameterName() const
+{
+ return m_parameterName;
+}
+
+void GeneratedParameter::setParameterName(const QString& parameterName)
+{
+ m_parameterName = parameterName;
+}
+
+GeneratedParameter::DataType GeneratedParameter::getParameterDataType() const
+{
+ return m_parameterDataType;
+}
+
+void GeneratedParameter::setParameterDataType(const DataType& parameterDataType)
+{
+ m_parameterDataType = parameterDataType;
+}
+
+QString GeneratedParameter::getParameterDescription() const
+{
+ return m_parameterDescription;
+}
+
+void GeneratedParameter::setParameterDescription(const QString& parameterDescription)
+{
+ m_parameterDescription = parameterDescription;
+}
+
+}
diff --git a/CodeGenerator/codegenerator.h b/CodeGenerator/codegenerator.h
index ecfba40..611bfbc 100644
--- a/CodeGenerator/codegenerator.h
+++ b/CodeGenerator/codegenerator.h
@@ -1,454 +1,454 @@
-// Copyright (C) 2020-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 .
-
-#ifndef CODEGENERATOR_H
-#define CODEGENERATOR_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace codegen
-{
-
-struct CodeGeneratorParameters
-{
- bool header = false;
- int indent = 0;
- QString className;
- bool isFirstItem = false;
- bool isLastItem = false;
-};
-
-class Serializer
-{
-public:
- static QObject* load(const QDomElement& element, QObject* parent);
- static void store(QObject* object, QDomElement& element);
- static QObject* clone(QObject* object, QObject* parent);
-
- template
- static inline QString convertEnumToString(T enumValue)
- {
- QMetaEnum metaEnum = QMetaEnum::fromType();
- Q_ASSERT(metaEnum.isValid());
- return metaEnum.valueToKey(enumValue);
- }
-
- template
- static inline void convertStringToEnum(const QString enumString, T& value)
- {
- QMetaEnum metaEnum = QMetaEnum::fromType();
- Q_ASSERT(metaEnum.isValid());
- bool ok = false;
- value = static_cast(metaEnum.keyToValue(enumString.toLatin1().data(), &ok));
- if (!ok)
- {
- // Set default value, if something fails.
- value = T();
- }
- }
-
- template
- static inline void fillComboBox(QComboBox* comboBox, T value)
- {
- QMetaEnum metaEnum = QMetaEnum::fromType();
- Q_ASSERT(metaEnum.isValid());
-
- const int keyCount = metaEnum.keyCount();
- comboBox->setUpdatesEnabled(false);
- comboBox->clear();
- for (int i = 0; i < keyCount; ++i)
- {
- comboBox->addItem(metaEnum.key(i), metaEnum.value(i));
- }
- comboBox->setCurrentIndex(comboBox->findData(int(value)));
- comboBox->setUpdatesEnabled(true);
- }
-};
-
-class GeneratedFunction;
-
-class GeneratedCodeStorage : public QObject
-{
- Q_OBJECT
-
-private:
- using BaseClass = QObject;
-
-public:
- Q_INVOKABLE GeneratedCodeStorage(QObject* parent);
-
- Q_PROPERTY(QObjectList functions READ getFunctions WRITE setFunctions)
-
- QObjectList getFunctions() const;
- void setFunctions(const QObjectList& functions);
-
- GeneratedFunction* addFunction(const QString& name);
- GeneratedFunction* addFunction(GeneratedFunction* function);
- void removeFunction(GeneratedFunction* function);
-
- void generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
-
-private:
- QObjectList m_functions;
-};
-
-class GeneratedBase : public QObject
-{
- Q_OBJECT
-
-private:
- using BaseClass = QObject;
-
-public:
- using BaseClass::BaseClass;
-
- enum class FieldType
- {
- Name,
- ItemType,
- DataType,
- Value,
- Description
- };
-
- enum DataType
- {
- _void,
- _PDFNull,
- _bool,
- _PDFInteger,
- _PDFReal,
- _PDFObjectReference,
- _PDFObject,
- _PDFIntegerVector,
- _PDFObjectReferenceVector,
- _PDFFormSubmitFlags,
- _QString,
- _QPointF,
- _QRectF,
- _QColor,
- _QVariant,
- _QPolygonF,
- _QDateTime,
- _QLocale,
- _QByteArray,
- _Polygons,
- _TextAnnotationIcon,
- _LinkHighlightMode,
- _TextAlignment,
- _AnnotationLineEnding,
- _AnnotationBorderStyle,
- _FileAttachmentIcon,
- _Stamp,
- _PDFDestination,
- _PageRotation
- };
- Q_ENUM(DataType)
-
- Q_PROPERTY(QObjectList items READ getItems WRITE setItems)
-
- virtual bool hasField(FieldType fieldType) const = 0;
- virtual QVariant readField(FieldType fieldType) const = 0;
- virtual void writeField(FieldType fieldType, QVariant value) = 0;
- virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) = 0;
- virtual bool canHaveSubitems() const = 0;
- virtual QStringList getCaptions() const = 0;
- virtual GeneratedBase* appendItem() = 0;
-
- enum class Pass
- {
- Enter,
- Leave
- };
-
- void generateSourceCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
- void applyFunctor(std::function& functor) const;
-
- enum class Operation
- {
- Delete,
- MoveUp,
- MoveDown,
- NewSibling,
- NewChild
- };
-
- GeneratedBase* getParent() { return qobject_cast(parent()); }
- const GeneratedBase* getParent() const { return qobject_cast(parent()); }
- bool canPerformOperation(Operation operation) const;
- void performOperation(Operation operation);
-
- QObjectList getItems() const;
- void setItems(const QObjectList& items);
- void addItem(QObject* object);
- void removeItem(QObject* object);
- void clearItems();
-
-protected:
- virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const;
-
- QString getCppType(DataType type) const;
- QStringList getFormattedTextWithLayout(QString firstPrefix, QString prefix, QString text, int indent) const;
- QStringList getFormattedTextBlock(QString firstPrefix, QString prefix, QStringList texts, int indent) const;
-
-private:
- QObjectList m_items;
-};
-
-class GeneratedParameter : public GeneratedBase
-{
- Q_OBJECT
-
-private:
- using BaseClass = GeneratedBase;
-
-public:
- Q_INVOKABLE GeneratedParameter(QObject* parent);
- Q_PROPERTY(QString parameterName READ getParameterName WRITE setParameterName)
- Q_PROPERTY(DataType parameterType READ getParameterDataType WRITE setParameterDataType)
- Q_PROPERTY(QString parameterDescription READ getParameterDescription WRITE setParameterDescription)
-
- virtual bool hasField(FieldType fieldType) const override;
- virtual QVariant readField(FieldType fieldType) const override;
- virtual void writeField(FieldType fieldType, QVariant value) override;
- virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override;
- virtual bool canHaveSubitems() const override;
- virtual QStringList getCaptions() const override;
- virtual GeneratedBase* appendItem() override;
-
- QString getParameterName() const;
- void setParameterName(const QString& parameterName);
-
- DataType getParameterDataType() const;
- void setParameterDataType(const DataType& parameterDataType);
-
- QString getParameterDescription() const;
- void setParameterDescription(const QString& parameterDescription);
-
-private:
- QString m_parameterName;
- DataType m_parameterDataType = _void;
- QString m_parameterDescription;
-};
-
-class GeneratedPDFObject : public GeneratedBase
-{
- Q_OBJECT
-
-private:
- using BaseClass = GeneratedBase;
-
-public:
-
- enum ObjectType
- {
- Object,
- ArraySimple,
- ArrayComplex,
- Dictionary,
- DictionaryItemSimple,
- DictionaryItemComplex
- };
- Q_ENUM(ObjectType)
-
- Q_INVOKABLE GeneratedPDFObject(QObject* parent);
- Q_PROPERTY(QString dictionaryItemName READ getDictionaryItemName WRITE setDictionaryItemName)
- Q_PROPERTY(ObjectType objectType READ getObjectType WRITE setObjectType)
- Q_PROPERTY(QString value READ getValue WRITE setValue)
-
- virtual bool hasField(FieldType fieldType) const override;
- virtual QVariant readField(FieldType fieldType) const override;
- virtual void writeField(FieldType fieldType, QVariant value) override;
- virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override;
- virtual bool canHaveSubitems() const override;
- virtual QStringList getCaptions() const override;
- virtual GeneratedBase* appendItem() override;
-
- QString getValue() const;
- void setValue(const QString& value);
-
- ObjectType getObjectType() const;
- void setObjectType(ObjectType objectType);
-
- QString getDictionaryItemName() const;
- void setDictionaryItemName(const QString& dictionaryItemName);
-
-protected:
- virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const override;
-
-private:
- QString m_dictionaryItemName;
- ObjectType m_objectType = Object;
- QString m_value;
-};
-
-class GeneratedAction : public GeneratedBase
-{
- Q_OBJECT
-
-private:
- using BaseClass = GeneratedBase;
-
-public:
-
- enum ActionType
- {
- Parameters,
- CreateObject,
- Code
- };
- Q_ENUM(ActionType)
-
- Q_INVOKABLE GeneratedAction(QObject* parent);
- Q_PROPERTY(ActionType actionType READ getActionType WRITE setActionType)
- Q_PROPERTY(QString variableName READ getVariableName WRITE setVariableName)
- Q_PROPERTY(DataType variableType READ getVariableType WRITE setVariableType)
- Q_PROPERTY(QString code READ getCode WRITE setCode)
-
- virtual bool hasField(FieldType fieldType) const override;
- virtual QVariant readField(FieldType fieldType) const override;
- virtual void writeField(FieldType fieldType, QVariant value) override;
- virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override;
- virtual bool canHaveSubitems() const override;
- virtual QStringList getCaptions() const override;
- virtual GeneratedBase* appendItem() override;
-
- ActionType getActionType() const;
- void setActionType(ActionType actionType);
-
- QString getVariableName() const;
- void setVariableName(const QString& variableName);
-
- DataType getVariableType() const;
- void setVariableType(DataType variableType);
-
- QString getCode() const;
- void setCode(const QString& code);
-
-protected:
- virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const override;
-
-private:
- ActionType m_actionType;
- QString m_variableName;
- DataType m_variableType = _void;
- QString m_code;
-};
-
-class GeneratedFunction : public GeneratedBase
-{
- Q_OBJECT
-
-private:
- using BaseClass = GeneratedBase;
-
-public:
-
- enum FunctionType
- {
- Structure,
- Annotations,
- ColorSpace,
- Actions,
- Forms
- };
- Q_ENUM(FunctionType)
-
-
- Q_INVOKABLE GeneratedFunction(QObject* parent);
-
- Q_PROPERTY(FunctionType functionType READ getFunctionType WRITE setFunctionType)
- Q_PROPERTY(QString functionName READ getFunctionName WRITE setFunctionName)
- Q_PROPERTY(QString functionDescription READ getFunctionDescription WRITE setFunctionDescription)
- Q_PROPERTY(DataType returnType READ getReturnType WRITE setReturnType)
-
- virtual bool hasField(FieldType fieldType) const override;
- virtual QVariant readField(FieldType fieldType) const override;
- virtual void writeField(FieldType fieldType, QVariant value) override;
- virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override;
- virtual bool canHaveSubitems() const override;
- virtual QStringList getCaptions() const override;
- virtual GeneratedBase* appendItem() override;
-
- QString getFunctionTypeString() const;
- void setFunctionTypeString(const QString& string);
-
- FunctionType getFunctionType() const;
- void setFunctionType(const FunctionType& functionType);
-
- QString getFunctionName() const;
- void setFunctionName(const QString& functionName);
-
- QString getFunctionDescription() const;
- void setFunctionDescription(const QString& functionDescription);
-
- DataType getReturnType() const;
- void setReturnType(DataType returnType);
-
- /// Create a clone of this function
- GeneratedFunction* clone(QObject* parent);
-
- void generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
-
-private:
- FunctionType m_functionType = FunctionType::Annotations;
- QString m_functionName;
- QString m_functionDescription;
- DataType m_returnType = _void;
-};
-
-class CodeGenerator : public QObject
-{
- Q_OBJECT
-
-private:
- using BaseClass = QObject;
-
-public:
- CodeGenerator(QObject* parent = nullptr);
-
- void initialize();
-
- QObjectList getFunctions() const { return m_storage->getFunctions(); }
- GeneratedFunction* addFunction(const QString& name) { return m_storage->addFunction(name); }
- GeneratedFunction* addFunction(GeneratedFunction* function) { return m_storage->addFunction(function); }
- void removeFunction(GeneratedFunction* function) { m_storage->removeFunction(function); }
-
- void load(const QDomDocument& document);
- void store(QDomDocument& document);
-
- void generateCode(QString headerName, QString sourceName) const;
-
-private:
- QString generateHeader(int indent) const;
- QString generateSource(QString className, int indent) const;
-
- GeneratedCodeStorage* m_storage = nullptr;
-};
-
-} // namespace codegen
-
-Q_DECLARE_METATYPE(codegen::GeneratedCodeStorage*)
-Q_DECLARE_METATYPE(codegen::GeneratedFunction*)
-
-#endif // CODEGENERATOR_H
+// Copyright (C) 2020-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 .
+
+#ifndef CODEGENERATOR_H
+#define CODEGENERATOR_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace codegen
+{
+
+struct CodeGeneratorParameters
+{
+ bool header = false;
+ int indent = 0;
+ QString className;
+ bool isFirstItem = false;
+ bool isLastItem = false;
+};
+
+class Serializer
+{
+public:
+ static QObject* load(const QDomElement& element, QObject* parent);
+ static void store(QObject* object, QDomElement& element);
+ static QObject* clone(QObject* object, QObject* parent);
+
+ template
+ static inline QString convertEnumToString(T enumValue)
+ {
+ QMetaEnum metaEnum = QMetaEnum::fromType();
+ Q_ASSERT(metaEnum.isValid());
+ return metaEnum.valueToKey(enumValue);
+ }
+
+ template
+ static inline void convertStringToEnum(const QString enumString, T& value)
+ {
+ QMetaEnum metaEnum = QMetaEnum::fromType();
+ Q_ASSERT(metaEnum.isValid());
+ bool ok = false;
+ value = static_cast(metaEnum.keyToValue(enumString.toLatin1().data(), &ok));
+ if (!ok)
+ {
+ // Set default value, if something fails.
+ value = T();
+ }
+ }
+
+ template
+ static inline void fillComboBox(QComboBox* comboBox, T value)
+ {
+ QMetaEnum metaEnum = QMetaEnum::fromType();
+ Q_ASSERT(metaEnum.isValid());
+
+ const int keyCount = metaEnum.keyCount();
+ comboBox->setUpdatesEnabled(false);
+ comboBox->clear();
+ for (int i = 0; i < keyCount; ++i)
+ {
+ comboBox->addItem(metaEnum.key(i), metaEnum.value(i));
+ }
+ comboBox->setCurrentIndex(comboBox->findData(int(value)));
+ comboBox->setUpdatesEnabled(true);
+ }
+};
+
+class GeneratedFunction;
+
+class GeneratedCodeStorage : public QObject
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = QObject;
+
+public:
+ Q_INVOKABLE GeneratedCodeStorage(QObject* parent);
+
+ Q_PROPERTY(QObjectList functions READ getFunctions WRITE setFunctions)
+
+ QObjectList getFunctions() const;
+ void setFunctions(const QObjectList& functions);
+
+ GeneratedFunction* addFunction(const QString& name);
+ GeneratedFunction* addFunction(GeneratedFunction* function);
+ void removeFunction(GeneratedFunction* function);
+
+ void generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
+
+private:
+ QObjectList m_functions;
+};
+
+class GeneratedBase : public QObject
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = QObject;
+
+public:
+ using BaseClass::BaseClass;
+
+ enum class FieldType
+ {
+ Name,
+ ItemType,
+ DataType,
+ Value,
+ Description
+ };
+
+ enum DataType
+ {
+ _void,
+ _PDFNull,
+ _bool,
+ _PDFInteger,
+ _PDFReal,
+ _PDFObjectReference,
+ _PDFObject,
+ _PDFIntegerVector,
+ _PDFObjectReferenceVector,
+ _PDFFormSubmitFlags,
+ _QString,
+ _QPointF,
+ _QRectF,
+ _QColor,
+ _QVariant,
+ _QPolygonF,
+ _QDateTime,
+ _QLocale,
+ _QByteArray,
+ _Polygons,
+ _TextAnnotationIcon,
+ _LinkHighlightMode,
+ _TextAlignment,
+ _AnnotationLineEnding,
+ _AnnotationBorderStyle,
+ _FileAttachmentIcon,
+ _Stamp,
+ _PDFDestination,
+ _PageRotation
+ };
+ Q_ENUM(DataType)
+
+ Q_PROPERTY(QObjectList items READ getItems WRITE setItems)
+
+ virtual bool hasField(FieldType fieldType) const = 0;
+ virtual QVariant readField(FieldType fieldType) const = 0;
+ virtual void writeField(FieldType fieldType, QVariant value) = 0;
+ virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) = 0;
+ virtual bool canHaveSubitems() const = 0;
+ virtual QStringList getCaptions() const = 0;
+ virtual GeneratedBase* appendItem() = 0;
+
+ enum class Pass
+ {
+ Enter,
+ Leave
+ };
+
+ void generateSourceCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
+ void applyFunctor(std::function& functor) const;
+
+ enum class Operation
+ {
+ Delete,
+ MoveUp,
+ MoveDown,
+ NewSibling,
+ NewChild
+ };
+
+ GeneratedBase* getParent() { return qobject_cast(parent()); }
+ const GeneratedBase* getParent() const { return qobject_cast(parent()); }
+ bool canPerformOperation(Operation operation) const;
+ void performOperation(Operation operation);
+
+ QObjectList getItems() const;
+ void setItems(const QObjectList& items);
+ void addItem(QObject* object);
+ void removeItem(QObject* object);
+ void clearItems();
+
+protected:
+ virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const;
+
+ QString getCppType(DataType type) const;
+ QStringList getFormattedTextWithLayout(QString firstPrefix, QString prefix, QString text, int indent) const;
+ QStringList getFormattedTextBlock(QString firstPrefix, QString prefix, QStringList texts, int indent) const;
+
+private:
+ QObjectList m_items;
+};
+
+class GeneratedParameter : public GeneratedBase
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = GeneratedBase;
+
+public:
+ Q_INVOKABLE GeneratedParameter(QObject* parent);
+ Q_PROPERTY(QString parameterName READ getParameterName WRITE setParameterName)
+ Q_PROPERTY(DataType parameterType READ getParameterDataType WRITE setParameterDataType)
+ Q_PROPERTY(QString parameterDescription READ getParameterDescription WRITE setParameterDescription)
+
+ virtual bool hasField(FieldType fieldType) const override;
+ virtual QVariant readField(FieldType fieldType) const override;
+ virtual void writeField(FieldType fieldType, QVariant value) override;
+ virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override;
+ virtual bool canHaveSubitems() const override;
+ virtual QStringList getCaptions() const override;
+ virtual GeneratedBase* appendItem() override;
+
+ QString getParameterName() const;
+ void setParameterName(const QString& parameterName);
+
+ DataType getParameterDataType() const;
+ void setParameterDataType(const DataType& parameterDataType);
+
+ QString getParameterDescription() const;
+ void setParameterDescription(const QString& parameterDescription);
+
+private:
+ QString m_parameterName;
+ DataType m_parameterDataType = _void;
+ QString m_parameterDescription;
+};
+
+class GeneratedPDFObject : public GeneratedBase
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = GeneratedBase;
+
+public:
+
+ enum ObjectType
+ {
+ Object,
+ ArraySimple,
+ ArrayComplex,
+ Dictionary,
+ DictionaryItemSimple,
+ DictionaryItemComplex
+ };
+ Q_ENUM(ObjectType)
+
+ Q_INVOKABLE GeneratedPDFObject(QObject* parent);
+ Q_PROPERTY(QString dictionaryItemName READ getDictionaryItemName WRITE setDictionaryItemName)
+ Q_PROPERTY(ObjectType objectType READ getObjectType WRITE setObjectType)
+ Q_PROPERTY(QString value READ getValue WRITE setValue)
+
+ virtual bool hasField(FieldType fieldType) const override;
+ virtual QVariant readField(FieldType fieldType) const override;
+ virtual void writeField(FieldType fieldType, QVariant value) override;
+ virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override;
+ virtual bool canHaveSubitems() const override;
+ virtual QStringList getCaptions() const override;
+ virtual GeneratedBase* appendItem() override;
+
+ QString getValue() const;
+ void setValue(const QString& value);
+
+ ObjectType getObjectType() const;
+ void setObjectType(ObjectType objectType);
+
+ QString getDictionaryItemName() const;
+ void setDictionaryItemName(const QString& dictionaryItemName);
+
+protected:
+ virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const override;
+
+private:
+ QString m_dictionaryItemName;
+ ObjectType m_objectType = Object;
+ QString m_value;
+};
+
+class GeneratedAction : public GeneratedBase
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = GeneratedBase;
+
+public:
+
+ enum ActionType
+ {
+ Parameters,
+ CreateObject,
+ Code
+ };
+ Q_ENUM(ActionType)
+
+ Q_INVOKABLE GeneratedAction(QObject* parent);
+ Q_PROPERTY(ActionType actionType READ getActionType WRITE setActionType)
+ Q_PROPERTY(QString variableName READ getVariableName WRITE setVariableName)
+ Q_PROPERTY(DataType variableType READ getVariableType WRITE setVariableType)
+ Q_PROPERTY(QString code READ getCode WRITE setCode)
+
+ virtual bool hasField(FieldType fieldType) const override;
+ virtual QVariant readField(FieldType fieldType) const override;
+ virtual void writeField(FieldType fieldType, QVariant value) override;
+ virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override;
+ virtual bool canHaveSubitems() const override;
+ virtual QStringList getCaptions() const override;
+ virtual GeneratedBase* appendItem() override;
+
+ ActionType getActionType() const;
+ void setActionType(ActionType actionType);
+
+ QString getVariableName() const;
+ void setVariableName(const QString& variableName);
+
+ DataType getVariableType() const;
+ void setVariableType(DataType variableType);
+
+ QString getCode() const;
+ void setCode(const QString& code);
+
+protected:
+ virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const override;
+
+private:
+ ActionType m_actionType;
+ QString m_variableName;
+ DataType m_variableType = _void;
+ QString m_code;
+};
+
+class GeneratedFunction : public GeneratedBase
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = GeneratedBase;
+
+public:
+
+ enum FunctionType
+ {
+ Structure,
+ Annotations,
+ ColorSpace,
+ Actions,
+ Forms
+ };
+ Q_ENUM(FunctionType)
+
+
+ Q_INVOKABLE GeneratedFunction(QObject* parent);
+
+ Q_PROPERTY(FunctionType functionType READ getFunctionType WRITE setFunctionType)
+ Q_PROPERTY(QString functionName READ getFunctionName WRITE setFunctionName)
+ Q_PROPERTY(QString functionDescription READ getFunctionDescription WRITE setFunctionDescription)
+ Q_PROPERTY(DataType returnType READ getReturnType WRITE setReturnType)
+
+ virtual bool hasField(FieldType fieldType) const override;
+ virtual QVariant readField(FieldType fieldType) const override;
+ virtual void writeField(FieldType fieldType, QVariant value) override;
+ virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override;
+ virtual bool canHaveSubitems() const override;
+ virtual QStringList getCaptions() const override;
+ virtual GeneratedBase* appendItem() override;
+
+ QString getFunctionTypeString() const;
+ void setFunctionTypeString(const QString& string);
+
+ FunctionType getFunctionType() const;
+ void setFunctionType(const FunctionType& functionType);
+
+ QString getFunctionName() const;
+ void setFunctionName(const QString& functionName);
+
+ QString getFunctionDescription() const;
+ void setFunctionDescription(const QString& functionDescription);
+
+ DataType getReturnType() const;
+ void setReturnType(DataType returnType);
+
+ /// Create a clone of this function
+ GeneratedFunction* clone(QObject* parent);
+
+ void generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
+
+private:
+ FunctionType m_functionType = FunctionType::Annotations;
+ QString m_functionName;
+ QString m_functionDescription;
+ DataType m_returnType = _void;
+};
+
+class CodeGenerator : public QObject
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = QObject;
+
+public:
+ CodeGenerator(QObject* parent = nullptr);
+
+ void initialize();
+
+ QObjectList getFunctions() const { return m_storage->getFunctions(); }
+ GeneratedFunction* addFunction(const QString& name) { return m_storage->addFunction(name); }
+ GeneratedFunction* addFunction(GeneratedFunction* function) { return m_storage->addFunction(function); }
+ void removeFunction(GeneratedFunction* function) { m_storage->removeFunction(function); }
+
+ void load(const QDomDocument& document);
+ void store(QDomDocument& document);
+
+ void generateCode(QString headerName, QString sourceName) const;
+
+private:
+ QString generateHeader(int indent) const;
+ QString generateSource(QString className, int indent) const;
+
+ GeneratedCodeStorage* m_storage = nullptr;
+};
+
+} // namespace codegen
+
+Q_DECLARE_METATYPE(codegen::GeneratedCodeStorage*)
+Q_DECLARE_METATYPE(codegen::GeneratedFunction*)
+
+#endif // CODEGENERATOR_H
diff --git a/CodeGenerator/generatormainwindow.cpp b/CodeGenerator/generatormainwindow.cpp
index 194f34e..c37dc43 100644
--- a/CodeGenerator/generatormainwindow.cpp
+++ b/CodeGenerator/generatormainwindow.cpp
@@ -1,523 +1,523 @@
-// Copyright (C) 2020-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 .
-
-#include "generatormainwindow.h"
-#include "ui_generatormainwindow.h"
-
-#include "codegenerator.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-GeneratorMainWindow::GeneratorMainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::GeneratorMainWindow),
- m_generator(new codegen::CodeGenerator(this)),
- m_currentFunction(nullptr),
- m_currentSettings(nullptr),
- m_isLoadingData(false)
-{
- ui->setupUi(this);
-
- ui->parameterTreeWidget->header()->setMinimumSectionSize(200);
-
- m_generator->initialize();
-
- loadSettings();
-
- if (!m_defaultFileName.isEmpty())
- {
- load(m_defaultFileName);
- }
- connect(ui->generatedFunctionsTreeWidget, &QTreeWidget::currentItemChanged, this, &GeneratorMainWindow::onCurrentItemChanged);
- connect(ui->parameterTreeWidget, &QTreeWidget::currentItemChanged, this, &GeneratorMainWindow::onParameterTreeCurrentItemChanged);
- connect(ui->parameterNameEdit, &QLineEdit::editingFinished, this, &GeneratorMainWindow::saveGeneratedSettings);
- connect(ui->parameterItemTypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &GeneratorMainWindow::saveGeneratedSettings);
- connect(ui->parameterDataTypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &GeneratorMainWindow::saveGeneratedSettings);
- connect(ui->parameterValueEdit, &QLineEdit::editingFinished, this, &GeneratorMainWindow::saveGeneratedSettings);
- connect(ui->parameterDescriptionEdit, &QTextBrowser::textChanged, this, &GeneratorMainWindow::saveGeneratedSettings);
-
- ui->parameterItemTypeCombo->setMaxVisibleItems(30);
- ui->parameterDataTypeCombo->setMaxVisibleItems(30);
-
- setWindowState(Qt::WindowMaximized);
- updateFunctionListUI();
-}
-
-GeneratorMainWindow::~GeneratorMainWindow()
-{
- delete ui;
-}
-
-void GeneratorMainWindow::load(const QString& fileName)
-{
- QFile file(fileName);
- if (file.open(QFile::ReadOnly | QFile::Truncate))
- {
- QTextStream stream(&file);
- stream.setCodec("UTF-8");
-
- QDomDocument document;
- document.setContent(stream.readAll());
- m_generator->load(document);
- file.close();
- }
-}
-
-void GeneratorMainWindow::saveSettings()
-{
- QSettings settings("MelkaJ");
- settings.setValue("fileName", m_defaultFileName);
- settings.setValue("headerFile", m_headerFileName);
- settings.setValue("sourceFile", m_sourceFileName);
-}
-
-void GeneratorMainWindow::loadGeneratedSettings()
-{
- BoolGuard guard(m_isLoadingData);
-
- const bool hasName = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Name);
- const bool hasItemType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::ItemType);
- const bool hasDataType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::DataType);
- const bool hasValue = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Value);
- const bool hasDescription = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Description);
-
- ui->parameterNameEdit->setEnabled(hasName);
- ui->parameterItemTypeCombo->setEnabled(hasItemType);
- ui->parameterDataTypeCombo->setEnabled(hasDataType);
- ui->parameterValueEdit->setEnabled(hasValue);
- ui->parameterDescriptionEdit->setEnabled(hasDescription);
-
- if (hasName)
- {
- ui->parameterNameEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Name).toString());
- }
- else
- {
- ui->parameterNameEdit->clear();
- }
-
- if (hasItemType)
- {
- m_currentSettings->fillComboBox(ui->parameterItemTypeCombo, codegen::GeneratedBase::FieldType::ItemType);
- }
- else
- {
- ui->parameterItemTypeCombo->clear();
- }
-
- if (hasDataType)
- {
- m_currentSettings->fillComboBox(ui->parameterDataTypeCombo, codegen::GeneratedBase::FieldType::DataType);
- }
- else
- {
- ui->parameterDataTypeCombo->clear();
- }
-
- if (hasValue)
- {
- ui->parameterValueEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Value).toString());
- }
- else
- {
- ui->parameterValueEdit->clear();
- }
-
- if (hasDescription)
- {
- ui->parameterDescriptionEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Description).toString());
- }
- else
- {
- ui->parameterDescriptionEdit->clear();
- }
-
- ui->itemDeleteButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::Delete));
- ui->itemUpButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::MoveUp));
- ui->itemDownButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::MoveDown));
- ui->itemNewSiblingButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::NewSibling));
- ui->itemNewChildButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::NewChild));
-}
-
-void GeneratorMainWindow::saveGeneratedSettings()
-{
- if (m_isLoadingData || !m_currentSettings)
- {
- return;
- }
-
- const bool hasName = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Name);
- const bool hasItemType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::ItemType);
- const bool hasDataType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::DataType);
- const bool hasValue = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Value);
- const bool hasDescription = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Description);
-
- m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Name, hasName ? ui->parameterNameEdit->text() : QVariant());
- m_currentSettings->writeField(codegen::GeneratedBase::FieldType::ItemType, hasItemType ? ui->parameterItemTypeCombo->currentData() : QVariant());
- m_currentSettings->writeField(codegen::GeneratedBase::FieldType::DataType, hasDataType ? ui->parameterDataTypeCombo->currentData() : QVariant());
- m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Value, hasValue ? ui->parameterValueEdit->text() : QVariant());
- m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Description, hasDescription ? ui->parameterDescriptionEdit->toPlainText() : QVariant());
-
- if (sender() != ui->parameterDescriptionEdit)
- {
- loadGeneratedSettings();
-
- // Update the captions
- std::function updateFunction = [&](QTreeWidgetItem* item)
- {
- const codegen::GeneratedBase* generatedBase = item->data(0, Qt::UserRole).value();
- QStringList captions = generatedBase->getCaptions();
-
- for (int i = 0; i < captions.size(); ++i)
- {
- item->setText(i, captions[i]);
- }
-
- for (int i = 0; i < item->childCount(); ++i)
- {
- updateFunction(item->child(i));
- }
- };
- updateFunction(ui->parameterTreeWidget->topLevelItem(0));
- }
-}
-
-void GeneratorMainWindow::updateFunctionListUI()
-{
- BoolGuard guard(m_isLoadingData);
-
- ui->generatedFunctionsTreeWidget->setUpdatesEnabled(false);
- ui->generatedFunctionsTreeWidget->clear();
- m_mapFunctionToWidgetItem.clear();
-
- // First, create roots
- std::map mapFunctionTypeToRoot;
- for (QObject* functionObject : m_generator->getFunctions())
- {
- codegen::GeneratedFunction* function = qobject_cast(functionObject);
- Q_ASSERT(function);
-
- if (!mapFunctionTypeToRoot.count(function->getFunctionType()))
- {
- QTreeWidgetItem* subroot = new QTreeWidgetItem(ui->generatedFunctionsTreeWidget, QStringList(function->getFunctionTypeString()));
- subroot->setFlags(Qt::ItemIsEnabled);
- mapFunctionTypeToRoot[function->getFunctionType()] = subroot;
- }
- }
- ui->generatedFunctionsTreeWidget->sortByColumn(0, Qt::AscendingOrder);
-
- for (QObject* functionObject : m_generator->getFunctions())
- {
- codegen::GeneratedFunction* function = qobject_cast(functionObject);
- Q_ASSERT(function);
-
- QTreeWidgetItem* functionItem = new QTreeWidgetItem(mapFunctionTypeToRoot[function->getFunctionType()], QStringList(function->getFunctionName()));
- functionItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
- functionItem->setData(0, Qt::UserRole, QVariant::fromValue(function));
- m_mapFunctionToWidgetItem[function] = functionItem;
- }
-
- ui->generatedFunctionsTreeWidget->expandAll();
- ui->generatedFunctionsTreeWidget->setUpdatesEnabled(true);
-
- // Select current function
- auto it = m_mapFunctionToWidgetItem.find(m_currentFunction);
- if (it != m_mapFunctionToWidgetItem.cend())
- {
- ui->generatedFunctionsTreeWidget->setCurrentItem(it->second, 0, QItemSelectionModel::SelectCurrent);
- }
-}
-
-void GeneratorMainWindow::updateGeneratedSettingsTree()
-{
- BoolGuard guard(m_isLoadingData);
-
- ui->parameterTreeWidget->setUpdatesEnabled(false);
- ui->parameterTreeWidget->clear();
-
- QTreeWidgetItem* selected = nullptr;
- std::function createTree = [this, &selected, &createTree](codegen::GeneratedBase* generatedItem, QTreeWidgetItem* parent)
- {
- QTreeWidgetItem* item = nullptr;
- if (parent)
- {
- item = new QTreeWidgetItem(parent, generatedItem->getCaptions());
- }
- else
- {
- item = new QTreeWidgetItem(ui->parameterTreeWidget, generatedItem->getCaptions());
- }
-
- item->setData(0, Qt::UserRole, QVariant::fromValue(generatedItem));
-
- if (generatedItem == m_currentSettings)
- {
- selected = item;
- }
-
- for (QObject* object : generatedItem->getItems())
- {
- createTree(qobject_cast(object), item);
- }
- };
-
- if (m_currentFunction)
- {
- createTree(m_currentFunction, nullptr);
- }
-
- ui->parameterTreeWidget->expandAll();
- ui->parameterTreeWidget->resizeColumnToContents(0);
- ui->parameterTreeWidget->setUpdatesEnabled(true);
-
- if (selected)
- {
- ui->parameterTreeWidget->setCurrentItem(selected, 0, QItemSelectionModel::SelectCurrent);
- }
-}
-
-void GeneratorMainWindow::setCurrentFunction(codegen::GeneratedFunction* currentFunction)
-{
- if (m_currentFunction != currentFunction)
- {
- BoolGuard guard(m_isLoadingData);
- m_currentFunction = currentFunction;
-
- // Select current function
- auto it = m_mapFunctionToWidgetItem.find(m_currentFunction);
- if (it != m_mapFunctionToWidgetItem.cend())
- {
- ui->generatedFunctionsTreeWidget->setCurrentItem(it->second, 0, QItemSelectionModel::SelectCurrent);
- ui->generatedFunctionsTreeWidget->setFocus();
- setCurrentSettings(m_currentFunction);
- updateGeneratedSettingsTree();
- }
- }
-}
-
-void GeneratorMainWindow::setCurrentSettings(codegen::GeneratedBase* currentSettings)
-{
- if (m_currentSettings != currentSettings)
- {
- BoolGuard guard(m_isLoadingData);
- m_currentSettings = currentSettings;
- loadGeneratedSettings();
- }
-}
-
-void GeneratorMainWindow::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
-{
- Q_UNUSED(previous);
-
- if (m_isLoadingData)
- {
- return;
- }
-
- codegen::GeneratedFunction* function = current->data(0, Qt::UserRole).value();
- setCurrentFunction(function);
-}
-
-void GeneratorMainWindow::onParameterTreeCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
-{
- Q_UNUSED(previous);
-
- if (m_isLoadingData)
- {
- return;
- }
-
- codegen::GeneratedBase* baseObject = current->data(0, Qt::UserRole).value();
- setCurrentSettings(baseObject);
-}
-
-void GeneratorMainWindow::loadSettings()
-{
- QSettings settings("MelkaJ");
- m_defaultFileName = settings.value("fileName").toString();
- m_headerFileName = settings.value("headerFile", QVariant()).toString();
- m_sourceFileName = settings.value("sourceFile", QVariant()).toString();
-}
-
-void GeneratorMainWindow::save(const QString& fileName)
-{
- QFile file(fileName);
- if (file.open(QFile::WriteOnly | QFile::Truncate))
- {
- QTextStream stream(&file);
- stream.setCodec("UTF-8");
-
- QDomDocument document;
- m_generator->store(document);
- document.save(stream, 2, QDomDocument::EncodingFromTextStream);
- file.close();
-
- // Update default file name
- m_defaultFileName = fileName;
- saveSettings();
- }
-}
-
-void GeneratorMainWindow::on_actionLoad_triggered()
-{
- QFileInfo info(m_defaultFileName);
- QString fileName = QFileDialog::getOpenFileName(this, tr("Select XML definition file"), info.dir().absolutePath(), "XML files (*.xml)");
- if (!fileName.isEmpty())
- {
- m_defaultFileName = fileName;
- saveSettings();
-
- load(m_defaultFileName);
- }
-}
-
-void GeneratorMainWindow::on_actionSaveAs_triggered()
-{
- QFileInfo info(m_defaultFileName);
- QString fileName = QFileDialog::getSaveFileName(this, tr("Select XML definition file"), info.dir().absolutePath(), "XML files (*.xml)");
- if (!fileName.isEmpty())
- {
- save(fileName);
- }
-}
-
-void GeneratorMainWindow::on_actionSave_triggered()
-{
- if (!m_defaultFileName.isEmpty())
- {
- save(m_defaultFileName);
- }
- else
- {
- on_actionSaveAs_triggered();
- }
-}
-
-void GeneratorMainWindow::on_newFunctionButton_clicked()
-{
- QString functionName = QInputDialog::getText(this, tr("Create function"), tr("Enter function name"));
- if (!functionName.isEmpty())
- {
- codegen::GeneratedFunction* generatedFunction = m_generator->addFunction(functionName);
- updateFunctionListUI();
- setCurrentFunction(generatedFunction);
- }
-}
-
-void GeneratorMainWindow::on_cloneFunctionButton_clicked()
-{
- if (m_currentFunction)
- {
- codegen::GeneratedFunction* generatedFunction = m_generator->addFunction(m_currentFunction->clone(nullptr));
- updateFunctionListUI();
- setCurrentFunction(generatedFunction);
- }
-}
-
-void GeneratorMainWindow::on_removeFunctionButton_clicked()
-{
- if (m_currentFunction)
- {
- codegen::GeneratedFunction* functionToDelete = m_currentFunction;
- setCurrentFunction(nullptr);
- m_generator->removeFunction(functionToDelete);
- updateFunctionListUI();
- }
-}
-
-void GeneratorMainWindow::on_itemDeleteButton_clicked()
-{
- if (m_currentSettings)
- {
- m_currentSettings->performOperation(codegen::GeneratedBase::Operation::Delete);
- setCurrentSettings(m_currentFunction);
- updateGeneratedSettingsTree();
- }
-}
-
-void GeneratorMainWindow::on_itemUpButton_clicked()
-{
- if (m_currentSettings)
- {
- m_currentSettings->performOperation(codegen::GeneratedBase::Operation::MoveUp);
- updateGeneratedSettingsTree();
- loadGeneratedSettings();
- }
-}
-
-void GeneratorMainWindow::on_itemDownButton_clicked()
-{
- if (m_currentSettings)
- {
- m_currentSettings->performOperation(codegen::GeneratedBase::Operation::MoveDown);
- updateGeneratedSettingsTree();
- loadGeneratedSettings();
- }
-}
-
-void GeneratorMainWindow::on_itemNewChildButton_clicked()
-{
- if (m_currentSettings)
- {
- m_currentSettings->performOperation(codegen::GeneratedBase::Operation::NewChild);
- updateGeneratedSettingsTree();
- loadGeneratedSettings();
- }
-}
-
-void GeneratorMainWindow::on_itemNewSiblingButton_clicked()
-{
- if (m_currentSettings)
- {
- m_currentSettings->performOperation(codegen::GeneratedBase::Operation::NewSibling);
- updateGeneratedSettingsTree();
- loadGeneratedSettings();
- }
-}
-
-void GeneratorMainWindow::on_actionSet_code_header_h_triggered()
-{
- QString fileName = QFileDialog::getOpenFileName(this, tr("Select cpp header"), QString(), "cpp header (*.h)");
- if (!fileName.isEmpty())
- {
- m_headerFileName = fileName;
- saveSettings();
- }
-}
-
-void GeneratorMainWindow::on_actionSet_code_source_cpp_triggered()
-{
- QString fileName = QFileDialog::getOpenFileName(this, tr("Select cpp source"), QString(), "cpp source (*.cpp)");
- if (!fileName.isEmpty())
- {
- m_sourceFileName = fileName;
- saveSettings();
- }
-}
-
-void GeneratorMainWindow::on_actionGenerate_code_triggered()
-{
- if (m_generator)
- {
- m_generator->generateCode(m_headerFileName, m_sourceFileName);
- }
-}
+// Copyright (C) 2020-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 .
+
+#include "generatormainwindow.h"
+#include "ui_generatormainwindow.h"
+
+#include "codegenerator.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+GeneratorMainWindow::GeneratorMainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::GeneratorMainWindow),
+ m_generator(new codegen::CodeGenerator(this)),
+ m_currentFunction(nullptr),
+ m_currentSettings(nullptr),
+ m_isLoadingData(false)
+{
+ ui->setupUi(this);
+
+ ui->parameterTreeWidget->header()->setMinimumSectionSize(200);
+
+ m_generator->initialize();
+
+ loadSettings();
+
+ if (!m_defaultFileName.isEmpty())
+ {
+ load(m_defaultFileName);
+ }
+ connect(ui->generatedFunctionsTreeWidget, &QTreeWidget::currentItemChanged, this, &GeneratorMainWindow::onCurrentItemChanged);
+ connect(ui->parameterTreeWidget, &QTreeWidget::currentItemChanged, this, &GeneratorMainWindow::onParameterTreeCurrentItemChanged);
+ connect(ui->parameterNameEdit, &QLineEdit::editingFinished, this, &GeneratorMainWindow::saveGeneratedSettings);
+ connect(ui->parameterItemTypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &GeneratorMainWindow::saveGeneratedSettings);
+ connect(ui->parameterDataTypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &GeneratorMainWindow::saveGeneratedSettings);
+ connect(ui->parameterValueEdit, &QLineEdit::editingFinished, this, &GeneratorMainWindow::saveGeneratedSettings);
+ connect(ui->parameterDescriptionEdit, &QTextBrowser::textChanged, this, &GeneratorMainWindow::saveGeneratedSettings);
+
+ ui->parameterItemTypeCombo->setMaxVisibleItems(30);
+ ui->parameterDataTypeCombo->setMaxVisibleItems(30);
+
+ setWindowState(Qt::WindowMaximized);
+ updateFunctionListUI();
+}
+
+GeneratorMainWindow::~GeneratorMainWindow()
+{
+ delete ui;
+}
+
+void GeneratorMainWindow::load(const QString& fileName)
+{
+ QFile file(fileName);
+ if (file.open(QFile::ReadOnly | QFile::Truncate))
+ {
+ QTextStream stream(&file);
+ stream.setCodec("UTF-8");
+
+ QDomDocument document;
+ document.setContent(stream.readAll());
+ m_generator->load(document);
+ file.close();
+ }
+}
+
+void GeneratorMainWindow::saveSettings()
+{
+ QSettings settings("MelkaJ");
+ settings.setValue("fileName", m_defaultFileName);
+ settings.setValue("headerFile", m_headerFileName);
+ settings.setValue("sourceFile", m_sourceFileName);
+}
+
+void GeneratorMainWindow::loadGeneratedSettings()
+{
+ BoolGuard guard(m_isLoadingData);
+
+ const bool hasName = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Name);
+ const bool hasItemType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::ItemType);
+ const bool hasDataType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::DataType);
+ const bool hasValue = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Value);
+ const bool hasDescription = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Description);
+
+ ui->parameterNameEdit->setEnabled(hasName);
+ ui->parameterItemTypeCombo->setEnabled(hasItemType);
+ ui->parameterDataTypeCombo->setEnabled(hasDataType);
+ ui->parameterValueEdit->setEnabled(hasValue);
+ ui->parameterDescriptionEdit->setEnabled(hasDescription);
+
+ if (hasName)
+ {
+ ui->parameterNameEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Name).toString());
+ }
+ else
+ {
+ ui->parameterNameEdit->clear();
+ }
+
+ if (hasItemType)
+ {
+ m_currentSettings->fillComboBox(ui->parameterItemTypeCombo, codegen::GeneratedBase::FieldType::ItemType);
+ }
+ else
+ {
+ ui->parameterItemTypeCombo->clear();
+ }
+
+ if (hasDataType)
+ {
+ m_currentSettings->fillComboBox(ui->parameterDataTypeCombo, codegen::GeneratedBase::FieldType::DataType);
+ }
+ else
+ {
+ ui->parameterDataTypeCombo->clear();
+ }
+
+ if (hasValue)
+ {
+ ui->parameterValueEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Value).toString());
+ }
+ else
+ {
+ ui->parameterValueEdit->clear();
+ }
+
+ if (hasDescription)
+ {
+ ui->parameterDescriptionEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Description).toString());
+ }
+ else
+ {
+ ui->parameterDescriptionEdit->clear();
+ }
+
+ ui->itemDeleteButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::Delete));
+ ui->itemUpButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::MoveUp));
+ ui->itemDownButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::MoveDown));
+ ui->itemNewSiblingButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::NewSibling));
+ ui->itemNewChildButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::NewChild));
+}
+
+void GeneratorMainWindow::saveGeneratedSettings()
+{
+ if (m_isLoadingData || !m_currentSettings)
+ {
+ return;
+ }
+
+ const bool hasName = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Name);
+ const bool hasItemType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::ItemType);
+ const bool hasDataType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::DataType);
+ const bool hasValue = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Value);
+ const bool hasDescription = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Description);
+
+ m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Name, hasName ? ui->parameterNameEdit->text() : QVariant());
+ m_currentSettings->writeField(codegen::GeneratedBase::FieldType::ItemType, hasItemType ? ui->parameterItemTypeCombo->currentData() : QVariant());
+ m_currentSettings->writeField(codegen::GeneratedBase::FieldType::DataType, hasDataType ? ui->parameterDataTypeCombo->currentData() : QVariant());
+ m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Value, hasValue ? ui->parameterValueEdit->text() : QVariant());
+ m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Description, hasDescription ? ui->parameterDescriptionEdit->toPlainText() : QVariant());
+
+ if (sender() != ui->parameterDescriptionEdit)
+ {
+ loadGeneratedSettings();
+
+ // Update the captions
+ std::function updateFunction = [&](QTreeWidgetItem* item)
+ {
+ const codegen::GeneratedBase* generatedBase = item->data(0, Qt::UserRole).value();
+ QStringList captions = generatedBase->getCaptions();
+
+ for (int i = 0; i < captions.size(); ++i)
+ {
+ item->setText(i, captions[i]);
+ }
+
+ for (int i = 0; i < item->childCount(); ++i)
+ {
+ updateFunction(item->child(i));
+ }
+ };
+ updateFunction(ui->parameterTreeWidget->topLevelItem(0));
+ }
+}
+
+void GeneratorMainWindow::updateFunctionListUI()
+{
+ BoolGuard guard(m_isLoadingData);
+
+ ui->generatedFunctionsTreeWidget->setUpdatesEnabled(false);
+ ui->generatedFunctionsTreeWidget->clear();
+ m_mapFunctionToWidgetItem.clear();
+
+ // First, create roots
+ std::map mapFunctionTypeToRoot;
+ for (QObject* functionObject : m_generator->getFunctions())
+ {
+ codegen::GeneratedFunction* function = qobject_cast(functionObject);
+ Q_ASSERT(function);
+
+ if (!mapFunctionTypeToRoot.count(function->getFunctionType()))
+ {
+ QTreeWidgetItem* subroot = new QTreeWidgetItem(ui->generatedFunctionsTreeWidget, QStringList(function->getFunctionTypeString()));
+ subroot->setFlags(Qt::ItemIsEnabled);
+ mapFunctionTypeToRoot[function->getFunctionType()] = subroot;
+ }
+ }
+ ui->generatedFunctionsTreeWidget->sortByColumn(0, Qt::AscendingOrder);
+
+ for (QObject* functionObject : m_generator->getFunctions())
+ {
+ codegen::GeneratedFunction* function = qobject_cast(functionObject);
+ Q_ASSERT(function);
+
+ QTreeWidgetItem* functionItem = new QTreeWidgetItem(mapFunctionTypeToRoot[function->getFunctionType()], QStringList(function->getFunctionName()));
+ functionItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+ functionItem->setData(0, Qt::UserRole, QVariant::fromValue(function));
+ m_mapFunctionToWidgetItem[function] = functionItem;
+ }
+
+ ui->generatedFunctionsTreeWidget->expandAll();
+ ui->generatedFunctionsTreeWidget->setUpdatesEnabled(true);
+
+ // Select current function
+ auto it = m_mapFunctionToWidgetItem.find(m_currentFunction);
+ if (it != m_mapFunctionToWidgetItem.cend())
+ {
+ ui->generatedFunctionsTreeWidget->setCurrentItem(it->second, 0, QItemSelectionModel::SelectCurrent);
+ }
+}
+
+void GeneratorMainWindow::updateGeneratedSettingsTree()
+{
+ BoolGuard guard(m_isLoadingData);
+
+ ui->parameterTreeWidget->setUpdatesEnabled(false);
+ ui->parameterTreeWidget->clear();
+
+ QTreeWidgetItem* selected = nullptr;
+ std::function createTree = [this, &selected, &createTree](codegen::GeneratedBase* generatedItem, QTreeWidgetItem* parent)
+ {
+ QTreeWidgetItem* item = nullptr;
+ if (parent)
+ {
+ item = new QTreeWidgetItem(parent, generatedItem->getCaptions());
+ }
+ else
+ {
+ item = new QTreeWidgetItem(ui->parameterTreeWidget, generatedItem->getCaptions());
+ }
+
+ item->setData(0, Qt::UserRole, QVariant::fromValue(generatedItem));
+
+ if (generatedItem == m_currentSettings)
+ {
+ selected = item;
+ }
+
+ for (QObject* object : generatedItem->getItems())
+ {
+ createTree(qobject_cast(object), item);
+ }
+ };
+
+ if (m_currentFunction)
+ {
+ createTree(m_currentFunction, nullptr);
+ }
+
+ ui->parameterTreeWidget->expandAll();
+ ui->parameterTreeWidget->resizeColumnToContents(0);
+ ui->parameterTreeWidget->setUpdatesEnabled(true);
+
+ if (selected)
+ {
+ ui->parameterTreeWidget->setCurrentItem(selected, 0, QItemSelectionModel::SelectCurrent);
+ }
+}
+
+void GeneratorMainWindow::setCurrentFunction(codegen::GeneratedFunction* currentFunction)
+{
+ if (m_currentFunction != currentFunction)
+ {
+ BoolGuard guard(m_isLoadingData);
+ m_currentFunction = currentFunction;
+
+ // Select current function
+ auto it = m_mapFunctionToWidgetItem.find(m_currentFunction);
+ if (it != m_mapFunctionToWidgetItem.cend())
+ {
+ ui->generatedFunctionsTreeWidget->setCurrentItem(it->second, 0, QItemSelectionModel::SelectCurrent);
+ ui->generatedFunctionsTreeWidget->setFocus();
+ setCurrentSettings(m_currentFunction);
+ updateGeneratedSettingsTree();
+ }
+ }
+}
+
+void GeneratorMainWindow::setCurrentSettings(codegen::GeneratedBase* currentSettings)
+{
+ if (m_currentSettings != currentSettings)
+ {
+ BoolGuard guard(m_isLoadingData);
+ m_currentSettings = currentSettings;
+ loadGeneratedSettings();
+ }
+}
+
+void GeneratorMainWindow::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
+{
+ Q_UNUSED(previous);
+
+ if (m_isLoadingData)
+ {
+ return;
+ }
+
+ codegen::GeneratedFunction* function = current->data(0, Qt::UserRole).value();
+ setCurrentFunction(function);
+}
+
+void GeneratorMainWindow::onParameterTreeCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
+{
+ Q_UNUSED(previous);
+
+ if (m_isLoadingData)
+ {
+ return;
+ }
+
+ codegen::GeneratedBase* baseObject = current->data(0, Qt::UserRole).value();
+ setCurrentSettings(baseObject);
+}
+
+void GeneratorMainWindow::loadSettings()
+{
+ QSettings settings("MelkaJ");
+ m_defaultFileName = settings.value("fileName").toString();
+ m_headerFileName = settings.value("headerFile", QVariant()).toString();
+ m_sourceFileName = settings.value("sourceFile", QVariant()).toString();
+}
+
+void GeneratorMainWindow::save(const QString& fileName)
+{
+ QFile file(fileName);
+ if (file.open(QFile::WriteOnly | QFile::Truncate))
+ {
+ QTextStream stream(&file);
+ stream.setCodec("UTF-8");
+
+ QDomDocument document;
+ m_generator->store(document);
+ document.save(stream, 2, QDomDocument::EncodingFromTextStream);
+ file.close();
+
+ // Update default file name
+ m_defaultFileName = fileName;
+ saveSettings();
+ }
+}
+
+void GeneratorMainWindow::on_actionLoad_triggered()
+{
+ QFileInfo info(m_defaultFileName);
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select XML definition file"), info.dir().absolutePath(), "XML files (*.xml)");
+ if (!fileName.isEmpty())
+ {
+ m_defaultFileName = fileName;
+ saveSettings();
+
+ load(m_defaultFileName);
+ }
+}
+
+void GeneratorMainWindow::on_actionSaveAs_triggered()
+{
+ QFileInfo info(m_defaultFileName);
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Select XML definition file"), info.dir().absolutePath(), "XML files (*.xml)");
+ if (!fileName.isEmpty())
+ {
+ save(fileName);
+ }
+}
+
+void GeneratorMainWindow::on_actionSave_triggered()
+{
+ if (!m_defaultFileName.isEmpty())
+ {
+ save(m_defaultFileName);
+ }
+ else
+ {
+ on_actionSaveAs_triggered();
+ }
+}
+
+void GeneratorMainWindow::on_newFunctionButton_clicked()
+{
+ QString functionName = QInputDialog::getText(this, tr("Create function"), tr("Enter function name"));
+ if (!functionName.isEmpty())
+ {
+ codegen::GeneratedFunction* generatedFunction = m_generator->addFunction(functionName);
+ updateFunctionListUI();
+ setCurrentFunction(generatedFunction);
+ }
+}
+
+void GeneratorMainWindow::on_cloneFunctionButton_clicked()
+{
+ if (m_currentFunction)
+ {
+ codegen::GeneratedFunction* generatedFunction = m_generator->addFunction(m_currentFunction->clone(nullptr));
+ updateFunctionListUI();
+ setCurrentFunction(generatedFunction);
+ }
+}
+
+void GeneratorMainWindow::on_removeFunctionButton_clicked()
+{
+ if (m_currentFunction)
+ {
+ codegen::GeneratedFunction* functionToDelete = m_currentFunction;
+ setCurrentFunction(nullptr);
+ m_generator->removeFunction(functionToDelete);
+ updateFunctionListUI();
+ }
+}
+
+void GeneratorMainWindow::on_itemDeleteButton_clicked()
+{
+ if (m_currentSettings)
+ {
+ m_currentSettings->performOperation(codegen::GeneratedBase::Operation::Delete);
+ setCurrentSettings(m_currentFunction);
+ updateGeneratedSettingsTree();
+ }
+}
+
+void GeneratorMainWindow::on_itemUpButton_clicked()
+{
+ if (m_currentSettings)
+ {
+ m_currentSettings->performOperation(codegen::GeneratedBase::Operation::MoveUp);
+ updateGeneratedSettingsTree();
+ loadGeneratedSettings();
+ }
+}
+
+void GeneratorMainWindow::on_itemDownButton_clicked()
+{
+ if (m_currentSettings)
+ {
+ m_currentSettings->performOperation(codegen::GeneratedBase::Operation::MoveDown);
+ updateGeneratedSettingsTree();
+ loadGeneratedSettings();
+ }
+}
+
+void GeneratorMainWindow::on_itemNewChildButton_clicked()
+{
+ if (m_currentSettings)
+ {
+ m_currentSettings->performOperation(codegen::GeneratedBase::Operation::NewChild);
+ updateGeneratedSettingsTree();
+ loadGeneratedSettings();
+ }
+}
+
+void GeneratorMainWindow::on_itemNewSiblingButton_clicked()
+{
+ if (m_currentSettings)
+ {
+ m_currentSettings->performOperation(codegen::GeneratedBase::Operation::NewSibling);
+ updateGeneratedSettingsTree();
+ loadGeneratedSettings();
+ }
+}
+
+void GeneratorMainWindow::on_actionSet_code_header_h_triggered()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select cpp header"), QString(), "cpp header (*.h)");
+ if (!fileName.isEmpty())
+ {
+ m_headerFileName = fileName;
+ saveSettings();
+ }
+}
+
+void GeneratorMainWindow::on_actionSet_code_source_cpp_triggered()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select cpp source"), QString(), "cpp source (*.cpp)");
+ if (!fileName.isEmpty())
+ {
+ m_sourceFileName = fileName;
+ saveSettings();
+ }
+}
+
+void GeneratorMainWindow::on_actionGenerate_code_triggered()
+{
+ if (m_generator)
+ {
+ m_generator->generateCode(m_headerFileName, m_sourceFileName);
+ }
+}
diff --git a/CodeGenerator/generatormainwindow.h b/CodeGenerator/generatormainwindow.h
index b41cba3..dc510d2 100644
--- a/CodeGenerator/generatormainwindow.h
+++ b/CodeGenerator/generatormainwindow.h
@@ -1,109 +1,109 @@
-// Copyright (C) 2020-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 .
-
-#ifndef GENERATORMAINWINDOW_H
-#define GENERATORMAINWINDOW_H
-
-#include
-
-class QTreeWidgetItem;
-
-namespace codegen
-{
-class CodeGenerator;
-class GeneratedFunction;
-class GeneratedBase;
-}
-
-namespace Ui
-{
-class GeneratorMainWindow;
-}
-
-class BoolGuard
-{
-public:
- explicit inline BoolGuard(bool& value) :
- m_oldValue(value),
- m_value(&value)
- {
- *m_value = true;
- }
-
- inline ~BoolGuard()
- {
- *m_value = m_oldValue;
- }
-
-private:
- bool m_oldValue;
- bool* m_value;
-};
-
-class GeneratorMainWindow : public QMainWindow
-{
- Q_OBJECT
-
-public:
- GeneratorMainWindow(QWidget* parent = nullptr);
- virtual ~GeneratorMainWindow() override;
-
- void load(const QString& fileName);
- void save(const QString& fileName);
-
-private slots:
- void on_actionLoad_triggered();
- void on_actionSaveAs_triggered();
- void on_actionSave_triggered();
- void on_newFunctionButton_clicked();
- void on_cloneFunctionButton_clicked();
- void on_removeFunctionButton_clicked();
- void on_itemDeleteButton_clicked();
- void on_itemUpButton_clicked();
- void on_itemDownButton_clicked();
- void on_itemNewChildButton_clicked();
- void on_itemNewSiblingButton_clicked();
- void on_actionSet_code_header_h_triggered();
- void on_actionSet_code_source_cpp_triggered();
- void on_actionGenerate_code_triggered();
-
-private:
- void loadSettings();
- void saveSettings();
-
- void loadGeneratedSettings();
- void saveGeneratedSettings();
-
- void updateFunctionListUI();
- void updateGeneratedSettingsTree();
- void setCurrentFunction(codegen::GeneratedFunction* currentFunction);
- void setCurrentSettings(codegen::GeneratedBase* currentSettings);
- void onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
- void onParameterTreeCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
-
- Ui::GeneratorMainWindow* ui;
- codegen::CodeGenerator* m_generator;
- codegen::GeneratedFunction* m_currentFunction;
- codegen::GeneratedBase* m_currentSettings;
- QString m_defaultFileName;
- QString m_headerFileName;
- QString m_sourceFileName;
- std::map m_mapFunctionToWidgetItem;
- bool m_isLoadingData;
-};
-
-#endif // GENERATORMAINWINDOW_H
+// Copyright (C) 2020-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 .
+
+#ifndef GENERATORMAINWINDOW_H
+#define GENERATORMAINWINDOW_H
+
+#include
+
+class QTreeWidgetItem;
+
+namespace codegen
+{
+class CodeGenerator;
+class GeneratedFunction;
+class GeneratedBase;
+}
+
+namespace Ui
+{
+class GeneratorMainWindow;
+}
+
+class BoolGuard
+{
+public:
+ explicit inline BoolGuard(bool& value) :
+ m_oldValue(value),
+ m_value(&value)
+ {
+ *m_value = true;
+ }
+
+ inline ~BoolGuard()
+ {
+ *m_value = m_oldValue;
+ }
+
+private:
+ bool m_oldValue;
+ bool* m_value;
+};
+
+class GeneratorMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ GeneratorMainWindow(QWidget* parent = nullptr);
+ virtual ~GeneratorMainWindow() override;
+
+ void load(const QString& fileName);
+ void save(const QString& fileName);
+
+private slots:
+ void on_actionLoad_triggered();
+ void on_actionSaveAs_triggered();
+ void on_actionSave_triggered();
+ void on_newFunctionButton_clicked();
+ void on_cloneFunctionButton_clicked();
+ void on_removeFunctionButton_clicked();
+ void on_itemDeleteButton_clicked();
+ void on_itemUpButton_clicked();
+ void on_itemDownButton_clicked();
+ void on_itemNewChildButton_clicked();
+ void on_itemNewSiblingButton_clicked();
+ void on_actionSet_code_header_h_triggered();
+ void on_actionSet_code_source_cpp_triggered();
+ void on_actionGenerate_code_triggered();
+
+private:
+ void loadSettings();
+ void saveSettings();
+
+ void loadGeneratedSettings();
+ void saveGeneratedSettings();
+
+ void updateFunctionListUI();
+ void updateGeneratedSettingsTree();
+ void setCurrentFunction(codegen::GeneratedFunction* currentFunction);
+ void setCurrentSettings(codegen::GeneratedBase* currentSettings);
+ void onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
+ void onParameterTreeCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
+
+ Ui::GeneratorMainWindow* ui;
+ codegen::CodeGenerator* m_generator;
+ codegen::GeneratedFunction* m_currentFunction;
+ codegen::GeneratedBase* m_currentSettings;
+ QString m_defaultFileName;
+ QString m_headerFileName;
+ QString m_sourceFileName;
+ std::map m_mapFunctionToWidgetItem;
+ bool m_isLoadingData;
+};
+
+#endif // GENERATORMAINWINDOW_H
diff --git a/CodeGenerator/generatormainwindow.ui b/CodeGenerator/generatormainwindow.ui
index 35d5ebd..10fac04 100644
--- a/CodeGenerator/generatormainwindow.ui
+++ b/CodeGenerator/generatormainwindow.ui
@@ -1,290 +1,290 @@
-
-
- GeneratorMainWindow
-
-
-
- 0
- 0
- 1121
- 662
-
-
-
- Code Generator
-
-
-
- -
-
-
-
-
-
- true
-
-
- false
-
-
-
- 1
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Remove
-
-
-
- -
-
-
- Clone
-
-
-
- -
-
-
- New
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Parameters
-
-
-
-
-
-
- Data type
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- false
-
-
- Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
-
-
-
- -
-
-
- Value
-
-
-
- -
-
-
- Item type
-
-
-
- -
-
-
- Name
-
-
-
- -
-
-
- Text description / C++ code
-
-
-
- -
-
-
-
-
-
- -
-
-
- 2
-
-
- false
-
-
-
- 1
-
-
-
-
- 2
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Delete
-
-
-
- -
-
-
- Up
-
-
-
- -
-
-
- Down
-
-
-
- -
-
-
- New Child
-
-
-
- -
-
-
- New Sibling
-
-
-
-
-
-
-
-
-
-
-
-
-
- Load
-
-
- Ctrl+O
-
-
-
-
- Save
-
-
- Ctrl+S
-
-
-
-
- Save As...
-
-
-
-
- Set code header (*.h)
-
-
-
-
- Set code source (*.cpp)
-
-
-
-
- Generate code
-
-
- Ctrl+G
-
-
-
-
-
-
+
+
+ GeneratorMainWindow
+
+
+
+ 0
+ 0
+ 1121
+ 662
+
+
+
+ Code Generator
+
+
+
+ -
+
+
-
+
+
+ true
+
+
+ false
+
+
+
+ 1
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Remove
+
+
+
+ -
+
+
+ Clone
+
+
+
+ -
+
+
+ New
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Parameters
+
+
+
-
+
+
+ Data type
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ false
+
+
+ Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ Value
+
+
+
+ -
+
+
+ Item type
+
+
+
+ -
+
+
+ Name
+
+
+
+ -
+
+
+ Text description / C++ code
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ 2
+
+
+ false
+
+
+
+ 1
+
+
+
+
+ 2
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Delete
+
+
+
+ -
+
+
+ Up
+
+
+
+ -
+
+
+ Down
+
+
+
+ -
+
+
+ New Child
+
+
+
+ -
+
+
+ New Sibling
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Load
+
+
+ Ctrl+O
+
+
+
+
+ Save
+
+
+ Ctrl+S
+
+
+
+
+ Save As...
+
+
+
+
+ Set code header (*.h)
+
+
+
+
+ Set code source (*.cpp)
+
+
+
+
+ Generate code
+
+
+ Ctrl+G
+
+
+
+
+
+
diff --git a/CodeGenerator/main.cpp b/CodeGenerator/main.cpp
index 28ea8da..8bde156 100644
--- a/CodeGenerator/main.cpp
+++ b/CodeGenerator/main.cpp
@@ -1,30 +1,30 @@
-// Copyright (C) 2020-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 .
-
-#include "generatormainwindow.h"
-
-#include
-#include
-
-int main(int argc, char *argv[])
-{
- qSetGlobalQHashSeed(0);
- QApplication a(argc, argv);
- GeneratorMainWindow w;
- w.show();
- return a.exec();
-}
+// Copyright (C) 2020-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 .
+
+#include "generatormainwindow.h"
+
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ qSetGlobalQHashSeed(0);
+ QApplication a(argc, argv);
+ GeneratorMainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/JBIG2_Viewer/JBIG2_Viewer.pro b/JBIG2_Viewer/JBIG2_Viewer.pro
index f7580d3..fcaa889 100644
--- a/JBIG2_Viewer/JBIG2_Viewer.pro
+++ b/JBIG2_Viewer/JBIG2_Viewer.pro
@@ -1,36 +1,36 @@
-QT += core gui
-
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-CONFIG += c++11
-
-# The following define makes your compiler emit warnings if you use
-# any Qt feature that has been marked deprecated (the exact warnings
-# depend on your compiler). Please consult the documentation of the
-# deprecated API in order to know how to port your code away from it.
-DEFINES += QT_DEPRECATED_WARNINGS
-
-# You can also make your code fail to compile if it uses deprecated APIs.
-# In order to do so, uncomment the following line.
-# You can also select to disable deprecated APIs only up to a certain version of Qt.
-#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
-QMAKE_CXXFLAGS += /std:c++latest /utf-8
-
-INCLUDEPATH += $$PWD/../PDF4QtLib/Sources
-
-DESTDIR = $$OUT_PWD/..
-
-LIBS += -L$$OUT_PWD/..
-
-LIBS += -lPDF4QtLib
-
-SOURCES += \
- main.cpp \
- mainwindow.cpp
-
-HEADERS += \
- mainwindow.h
-
-FORMS += \
- mainwindow.ui
+QT += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++11
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+QMAKE_CXXFLAGS += /std:c++latest /utf-8
+
+INCLUDEPATH += $$PWD/../PDF4QtLib/Sources
+
+DESTDIR = $$OUT_PWD/..
+
+LIBS += -L$$OUT_PWD/..
+
+LIBS += -lPDF4QtLib
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+FORMS += \
+ mainwindow.ui
diff --git a/JBIG2_Viewer/main.cpp b/JBIG2_Viewer/main.cpp
index 9cfa17b..97190a8 100644
--- a/JBIG2_Viewer/main.cpp
+++ b/JBIG2_Viewer/main.cpp
@@ -1,33 +1,33 @@
-// 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 .
-
-#include "mainwindow.h"
-
-#include
-
-int main(int argc, char *argv[])
-{
- QApplication a(argc, argv);
-
- QCoreApplication::setOrganizationName("MelkaJ");
- QCoreApplication::setApplicationName("JBIG2_image_viewer");
- QCoreApplication::setApplicationVersion("1.0");
-
- MainWindow w;
- w.show();
- return a.exec();
-}
+// 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 .
+
+#include "mainwindow.h"
+
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ QCoreApplication::setOrganizationName("MelkaJ");
+ QCoreApplication::setApplicationName("JBIG2_image_viewer");
+ QCoreApplication::setApplicationVersion("1.0");
+
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/JBIG2_Viewer/mainwindow.cpp b/JBIG2_Viewer/mainwindow.cpp
index 592012b..a3e5f57 100644
--- a/JBIG2_Viewer/mainwindow.cpp
+++ b/JBIG2_Viewer/mainwindow.cpp
@@ -1,121 +1,121 @@
-#include "mainwindow.h"
-#include "ui_mainwindow.h"
-
-#include "pdfexception.h"
-#include "pdfjbig2decoder.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-MainWindow::MainWindow(QWidget* parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
-{
- ui->setupUi(this);
- setWindowState(Qt::WindowMaximized);
-
- QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
- m_directory = settings.value("Directory").toString();
-}
-
-MainWindow::~MainWindow()
-{
- QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
- settings.setValue("Directory", m_directory);
-
- delete ui;
-}
-
-void MainWindow::reportRenderError(pdf::RenderErrorType type, QString message)
-{
- Q_UNUSED(type);
- QMessageBox::critical(this, tr("Error"), message);
-}
-
-void MainWindow::on_actionAddImage_triggered()
-{
- QString fileName = QFileDialog::getOpenFileName(this, tr("Open image"), m_directory, QString("Bitmap image (*.bmp)"));
- if (QFile::exists(fileName))
- {
- QImageReader reader(fileName);
- QImage image = reader.read();
-
- if (!image.isNull())
- {
- QFileInfo file(fileName);
- m_directory = file.filePath();
- addImage(file.fileName(), qMove(image));
- }
- }
-}
-
-void MainWindow::addImage(QString title, QImage image)
-{
- QGroupBox* groupBox = new QGroupBox(this);
- QHBoxLayout* layout = new QHBoxLayout(groupBox);
- groupBox->setTitle(title);
- QLabel* label = new QLabel(groupBox);
- layout->addWidget(label);
- label->setPixmap(QPixmap::fromImage(image));
- label->setFixedSize(image.size());
- ui->imagesMainLayout->addWidget(groupBox);
-}
-
-void MainWindow::on_actionClear_triggered()
-{
- for (int i = 0; i < ui->imagesMainLayout->count(); ++i)
- {
- ui->imagesMainLayout->itemAt(i)->widget()->deleteLater();
- }
-}
-
-void MainWindow::on_actionAdd_JBIG2_image_triggered()
-{
- QString fileName = QFileDialog::getOpenFileName(this, tr("Open image"), m_directory, QString("JBIG2 image (*.jb2)"));
- if (QFile::exists(fileName))
- {
- QFile file(fileName);
- if (file.open(QFile::ReadOnly))
- {
- m_directory = QFileInfo(file).filePath();
- QByteArray data = file.readAll();
- file.close();
-
- try
- {
- pdf::PDFJBIG2Decoder decoder(data, QByteArray(), this);
-
- QElapsedTimer timer;
- timer.start();
- pdf::PDFImageData imageData = decoder.decodeFileStream();
- qint64 time = timer.elapsed();
-
- if (imageData.isValid())
- {
- QImage image(imageData.getWidth(), imageData.getHeight(), QImage::Format_Mono);
- const uchar* sourceData = reinterpret_cast(imageData.getData().constData());
- Q_ASSERT(imageData.getData().size() == image.byteCount());
- std::transform(sourceData, sourceData + imageData.getData().size(), image.bits(), [](const uchar value) { return value; });
- addImage(file.fileName() + QString(", Decoded in %1 [msec]").arg(time), qMove(image));
- }
- }
- catch (pdf::PDFException exception)
- {
- QMessageBox::critical(this, tr("Error"), exception.getMessage());
- }
- }
- }
-}
-
-void MainWindow::reportRenderErrorOnce(pdf::RenderErrorType type, QString message)
-{
- Q_UNUSED(type);
- QMessageBox::critical(this, tr("Error"), message);
-}
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include "pdfexception.h"
+#include "pdfjbig2decoder.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+MainWindow::MainWindow(QWidget* parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+ setWindowState(Qt::WindowMaximized);
+
+ QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
+ m_directory = settings.value("Directory").toString();
+}
+
+MainWindow::~MainWindow()
+{
+ QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
+ settings.setValue("Directory", m_directory);
+
+ delete ui;
+}
+
+void MainWindow::reportRenderError(pdf::RenderErrorType type, QString message)
+{
+ Q_UNUSED(type);
+ QMessageBox::critical(this, tr("Error"), message);
+}
+
+void MainWindow::on_actionAddImage_triggered()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Open image"), m_directory, QString("Bitmap image (*.bmp)"));
+ if (QFile::exists(fileName))
+ {
+ QImageReader reader(fileName);
+ QImage image = reader.read();
+
+ if (!image.isNull())
+ {
+ QFileInfo file(fileName);
+ m_directory = file.filePath();
+ addImage(file.fileName(), qMove(image));
+ }
+ }
+}
+
+void MainWindow::addImage(QString title, QImage image)
+{
+ QGroupBox* groupBox = new QGroupBox(this);
+ QHBoxLayout* layout = new QHBoxLayout(groupBox);
+ groupBox->setTitle(title);
+ QLabel* label = new QLabel(groupBox);
+ layout->addWidget(label);
+ label->setPixmap(QPixmap::fromImage(image));
+ label->setFixedSize(image.size());
+ ui->imagesMainLayout->addWidget(groupBox);
+}
+
+void MainWindow::on_actionClear_triggered()
+{
+ for (int i = 0; i < ui->imagesMainLayout->count(); ++i)
+ {
+ ui->imagesMainLayout->itemAt(i)->widget()->deleteLater();
+ }
+}
+
+void MainWindow::on_actionAdd_JBIG2_image_triggered()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Open image"), m_directory, QString("JBIG2 image (*.jb2)"));
+ if (QFile::exists(fileName))
+ {
+ QFile file(fileName);
+ if (file.open(QFile::ReadOnly))
+ {
+ m_directory = QFileInfo(file).filePath();
+ QByteArray data = file.readAll();
+ file.close();
+
+ try
+ {
+ pdf::PDFJBIG2Decoder decoder(data, QByteArray(), this);
+
+ QElapsedTimer timer;
+ timer.start();
+ pdf::PDFImageData imageData = decoder.decodeFileStream();
+ qint64 time = timer.elapsed();
+
+ if (imageData.isValid())
+ {
+ QImage image(imageData.getWidth(), imageData.getHeight(), QImage::Format_Mono);
+ const uchar* sourceData = reinterpret_cast(imageData.getData().constData());
+ Q_ASSERT(imageData.getData().size() == image.byteCount());
+ std::transform(sourceData, sourceData + imageData.getData().size(), image.bits(), [](const uchar value) { return value; });
+ addImage(file.fileName() + QString(", Decoded in %1 [msec]").arg(time), qMove(image));
+ }
+ }
+ catch (pdf::PDFException exception)
+ {
+ QMessageBox::critical(this, tr("Error"), exception.getMessage());
+ }
+ }
+ }
+}
+
+void MainWindow::reportRenderErrorOnce(pdf::RenderErrorType type, QString message)
+{
+ Q_UNUSED(type);
+ QMessageBox::critical(this, tr("Error"), message);
+}
diff --git a/JBIG2_Viewer/mainwindow.h b/JBIG2_Viewer/mainwindow.h
index 308a3ca..1e44e23 100644
--- a/JBIG2_Viewer/mainwindow.h
+++ b/JBIG2_Viewer/mainwindow.h
@@ -1,34 +1,34 @@
-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include
-
-#include "pdfexception.h"
-
-QT_BEGIN_NAMESPACE
-namespace Ui { class MainWindow; }
-QT_END_NAMESPACE
-
-class MainWindow : public QMainWindow, public pdf::PDFRenderErrorReporter
-{
- Q_OBJECT
-
-public:
- MainWindow(QWidget* parent = nullptr);
- virtual ~MainWindow() override;
-
- virtual void reportRenderError(pdf::RenderErrorType type, QString message) override;
- virtual void reportRenderErrorOnce(pdf::RenderErrorType type, QString message) override;
-
-private slots:
- void on_actionAddImage_triggered();
- void on_actionClear_triggered();
- void on_actionAdd_JBIG2_image_triggered();
-
-private:
- void addImage(QString title, QImage image);
-
- Ui::MainWindow* ui;
- QString m_directory;
-};
-#endif // MAINWINDOW_H
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+
+#include "pdfexception.h"
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class MainWindow; }
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow, public pdf::PDFRenderErrorReporter
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget* parent = nullptr);
+ virtual ~MainWindow() override;
+
+ virtual void reportRenderError(pdf::RenderErrorType type, QString message) override;
+ virtual void reportRenderErrorOnce(pdf::RenderErrorType type, QString message) override;
+
+private slots:
+ void on_actionAddImage_triggered();
+ void on_actionClear_triggered();
+ void on_actionAdd_JBIG2_image_triggered();
+
+private:
+ void addImage(QString title, QImage image);
+
+ Ui::MainWindow* ui;
+ QString m_directory;
+};
+#endif // MAINWINDOW_H
diff --git a/JBIG2_Viewer/mainwindow.ui b/JBIG2_Viewer/mainwindow.ui
index a75e54c..83148ba 100644
--- a/JBIG2_Viewer/mainwindow.ui
+++ b/JBIG2_Viewer/mainwindow.ui
@@ -1,110 +1,110 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 800
- 600
-
-
-
- JBIG2 Image Viewer
-
-
-
- -
-
-
- true
-
-
-
-
- 0
- 0
- 780
- 537
-
-
-
-
-
-
-
- Images
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Add image
-
-
- Ctrl+O
-
-
-
-
- Clear
-
-
- Ctrl+W
-
-
-
-
- Add JBIG2 image
-
-
- Ctrl+J
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 800
+ 600
+
+
+
+ JBIG2 Image Viewer
+
+
+
+ -
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 780
+ 537
+
+
+
+
-
+
+
+ Images
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add image
+
+
+ Ctrl+O
+
+
+
+
+ Clear
+
+
+ Ctrl+W
+
+
+
+
+ Add JBIG2 image
+
+
+ Ctrl+J
+
+
+
+
+
+
diff --git a/LICENSE.txt b/LICENSE.txt
index 11e8067..0a04128 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,165 +1,165 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
- This version of the GNU Lesser General Public License incorporates
-the terms and conditions of version 3 of the GNU General Public
-License, supplemented by the additional permissions listed below.
-
- 0. Additional Definitions.
-
- As used herein, "this License" refers to version 3 of the GNU Lesser
-General Public License, and the "GNU GPL" refers to version 3 of the GNU
-General Public License.
-
- "The Library" refers to a covered work governed by this License,
-other than an Application or a Combined Work as defined below.
-
- An "Application" is any work that makes use of an interface provided
-by the Library, but which is not otherwise based on the Library.
-Defining a subclass of a class defined by the Library is deemed a mode
-of using an interface provided by the Library.
-
- A "Combined Work" is a work produced by combining or linking an
-Application with the Library. The particular version of the Library
-with which the Combined Work was made is also called the "Linked
-Version".
-
- The "Minimal Corresponding Source" for a Combined Work means the
-Corresponding Source for the Combined Work, excluding any source code
-for portions of the Combined Work that, considered in isolation, are
-based on the Application, and not on the Linked Version.
-
- The "Corresponding Application Code" for a Combined Work means the
-object code and/or source code for the Application, including any data
-and utility programs needed for reproducing the Combined Work from the
-Application, but excluding the System Libraries of the Combined Work.
-
- 1. Exception to Section 3 of the GNU GPL.
-
- You may convey a covered work under sections 3 and 4 of this License
-without being bound by section 3 of the GNU GPL.
-
- 2. Conveying Modified Versions.
-
- If you modify a copy of the Library, and, in your modifications, a
-facility refers to a function or data to be supplied by an Application
-that uses the facility (other than as an argument passed when the
-facility is invoked), then you may convey a copy of the modified
-version:
-
- a) under this License, provided that you make a good faith effort to
- ensure that, in the event an Application does not supply the
- function or data, the facility still operates, and performs
- whatever part of its purpose remains meaningful, or
-
- b) under the GNU GPL, with none of the additional permissions of
- this License applicable to that copy.
-
- 3. Object Code Incorporating Material from Library Header Files.
-
- The object code form of an Application may incorporate material from
-a header file that is part of the Library. You may convey such object
-code under terms of your choice, provided that, if the incorporated
-material is not limited to numerical parameters, data structure
-layouts and accessors, or small macros, inline functions and templates
-(ten or fewer lines in length), you do both of the following:
-
- a) Give prominent notice with each copy of the object code that the
- Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the object code with a copy of the GNU GPL and this license
- document.
-
- 4. Combined Works.
-
- You may convey a Combined Work under terms of your choice that,
-taken together, effectively do not restrict modification of the
-portions of the Library contained in the Combined Work and reverse
-engineering for debugging such modifications, if you also do each of
-the following:
-
- a) Give prominent notice with each copy of the Combined Work that
- the Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
- document.
-
- c) For a Combined Work that displays copyright notices during
- execution, include the copyright notice for the Library among
- these notices, as well as a reference directing the user to the
- copies of the GNU GPL and this license document.
-
- d) Do one of the following:
-
- 0) Convey the Minimal Corresponding Source under the terms of this
- License, and the Corresponding Application Code in a form
- suitable for, and under terms that permit, the user to
- recombine or relink the Application with a modified version of
- the Linked Version to produce a modified Combined Work, in the
- manner specified by section 6 of the GNU GPL for conveying
- Corresponding Source.
-
- 1) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (a) uses at run time
- a copy of the Library already present on the user's computer
- system, and (b) will operate properly with a modified version
- of the Library that is interface-compatible with the Linked
- Version.
-
- e) Provide Installation Information, but only if you would otherwise
- be required to provide such information under section 6 of the
- GNU GPL, and only to the extent that such information is
- necessary to install and execute a modified version of the
- Combined Work produced by recombining or relinking the
- Application with a modified version of the Linked Version. (If
- you use option 4d0, the Installation Information must accompany
- the Minimal Corresponding Source and Corresponding Application
- Code. If you use option 4d1, you must provide the Installation
- Information in the manner specified by section 6 of the GNU GPL
- for conveying Corresponding Source.)
-
- 5. Combined Libraries.
-
- You may place library facilities that are a work based on the
-Library side by side in a single library together with other library
-facilities that are not Applications and are not covered by this
-License, and convey such a combined library under terms of your
-choice, if you do both of the following:
-
- a) Accompany the combined library with a copy of the same work based
- on the Library, uncombined with any other library facilities,
- conveyed under the terms of this License.
-
- b) Give prominent notice with the combined library that part of it
- is a work based on the Library, and explaining where to find the
- accompanying uncombined form of the same work.
-
- 6. Revised Versions of the GNU Lesser General Public License.
-
- The Free Software Foundation may publish revised and/or new versions
-of the GNU Lesser General Public License from time to time. Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Library as you received it specifies that a certain numbered version
-of the GNU Lesser General Public License "or any later version"
-applies to it, you have the option of following the terms and
-conditions either of that published version or of any later version
-published by the Free Software Foundation. If the Library as you
-received it does not specify a version number of the GNU Lesser
-General Public License, you may choose any version of the GNU Lesser
-General Public License ever published by the Free Software Foundation.
-
- If the Library as you received it specifies that a proxy can decide
-whether future versions of the GNU Lesser General Public License shall
-apply, that proxy's public statement of acceptance of any version is
-permanent authorization for you to choose that version for the
-Library.
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/NOTES.txt b/NOTES.txt
index b9a66b1..da7bdda 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -1,105 +1,105 @@
-
-Conformance to PDF 2.0 specification notes and tasks:
-
-Section 1: OK
-Section 2: OK
-Section 3: OK
-Section 4: OK
-Section 5: OK
-Section 6: OK
-
-Section 7: Issues
- - 7.4.7 JBIG2 decoder ammendments 1 and 2 not implemented
- - 7.6.5 Public-key security handlers not implemented
- - 7.6.7 Unencrypted wrapper document not implemented
- - 7.10.2 Only linear interpolation for sampled function is performed
-
-Section 8: Issues
- - 8.3.2.3 In user space, 1 / 72 inch is used, no UserUnit entry is used
- - 8.6.3 transfer functions and halftones are not used at all, color
- management system is used to convert colors
- - 8.6.5.6 No device to default color space is performed. Device color
- spaces can be set in color management system.
- - 8.6.5.8 default rendering intent is perceptual instead of relative colorimetric
- - 8.6.5.9 Black point compensation is user setting, graphic state setting
- is not respected (it is ignored)
- - 8.6.7 Overprint not implemented
- - 8.10.2 Some form dictionary entries, in table 93, are not all being processed
- - 8.10.4 Reference XObject is not supported. Instead, proxy is displayed.
-
-Section 9: Issues
- - 9.3.2 Negative font size is not supported
- - 9.3.8 Text knockout not implemented
- - 9.5 Some type of fonts not supported yet (CIDFont, some others)
- - 9.6.2.1 Missing width is not used for missing characters
- - 9.6.4 d1 operator incorrectly doesn't ignore color/alpha operators
- - 9.7.4 CIDSystemInfo ignored in Table 115
-
-Section 10: Issues
- - Color management system is used for color conversions. This can
- be turned of, and in that case, methods from 10.4.2 are used.
- Undercolor removal and black generation are not used.
- - 10.6 Halftoning is not implemented
- - 10.7.2 Flatness is ignored
- - 10.7.3 Smoothness is ignored
- - 10.7.5 Automatic stroke adjustment is ignored
- - 10.8 Separations are not produced
- - 10.8.3 Separation simulation is not performed
-
-Section 11: Implemented partially
- - Transparency is not implemented in regular Qt's painter,
- but separate transparency renderer exist, which can render
- also spot colors
-
-Section 12: Issues
- - 12.3.2.2 Destinations are used only to leap on specified page,
- position on page or fit hints are ignored
- - 12.3.5.2 File collection folders are ignored, files are
- displayed in a single list
- - 12.3.6 Navigator for file collections is ignored
- - 12.4.2 Page indices are used instead of labels
- - 12.4.4 Presentations are not implemented
- - 12.5.5 Annotation's transparency group is ignored
- - 12.5.6.3 Annotation's states are not implemented in viewer
- - 12.5.6.22 Watermark annotation - matrix and fixed print entry is not used
- - 12.6.3 Some trigger events are not executed or not implemented
- - 12.6.4 Some action are not executed in viewer
- - 12.6.4.8 URI actions doesn't use IsMap
- - 12.7.4.3 Variable text is implemented by Qt's QTextLayout
- and drawing, pdf's specific default appearance strings,
- and rich text is not implemented. This doesn't conform
- to PDF specification, but all unicode characters can be used.
- - 12.7.5.5 Signature field locking not implemented and signature
- seed dictionary is ignored
- - 12.7.6.2 Sumbit form action not implemented in viewer
- - 12.7.6.4 Import data action not implemented in viewer
- - 12.7.8 Form data format not implemented
- - 12.8 Modification detection using UR3/DocMDP method is not
- used, if signature is not valid, then it is not checked for
- modifications
- - 12.8 OCSP (Online Certificate Status Protocol) is not performed
- - 12.8.4 Long term validation of signatures not performed
- - 12.8.4.5 Validation data in custom VRI are not used, instead of them,
- validation data in DSS or embedded in the signature are used
- - 12.8.5 Document timestamp dictionary not implemented
- - 12.8.6 Permissions not implemented
- - 12.9 Measure feature not implemented
- - 12.10 Geospatial features not implemented
-
-Section 13: Not implemented
- - Multimedia features not implemented (except some classes, which
- can read the data for multimedia - movies, sounds...)
-
-Section 14: Issues
- - 14.3 Document metadata stream is not processed
- - 14.4 Modifiable file identifier is not updated
- - 14.5 Page-piece dictionaries not implemented
- - 14.9 Accessibility support not implemented
- - 14.10 Web capture not implemented
- - 14.11 Prepress support not implemented at all, only
- basic functionality works (media box, crop box, or,
- for example, reading output intents)
- - 14.12 Document parts not implemented
-
-Annex F: Not implemented
- - Linearized PDF not implemented
+
+Conformance to PDF 2.0 specification notes and tasks:
+
+Section 1: OK
+Section 2: OK
+Section 3: OK
+Section 4: OK
+Section 5: OK
+Section 6: OK
+
+Section 7: Issues
+ - 7.4.7 JBIG2 decoder ammendments 1 and 2 not implemented
+ - 7.6.5 Public-key security handlers not implemented
+ - 7.6.7 Unencrypted wrapper document not implemented
+ - 7.10.2 Only linear interpolation for sampled function is performed
+
+Section 8: Issues
+ - 8.3.2.3 In user space, 1 / 72 inch is used, no UserUnit entry is used
+ - 8.6.3 transfer functions and halftones are not used at all, color
+ management system is used to convert colors
+ - 8.6.5.6 No device to default color space is performed. Device color
+ spaces can be set in color management system.
+ - 8.6.5.8 default rendering intent is perceptual instead of relative colorimetric
+ - 8.6.5.9 Black point compensation is user setting, graphic state setting
+ is not respected (it is ignored)
+ - 8.6.7 Overprint not implemented
+ - 8.10.2 Some form dictionary entries, in table 93, are not all being processed
+ - 8.10.4 Reference XObject is not supported. Instead, proxy is displayed.
+
+Section 9: Issues
+ - 9.3.2 Negative font size is not supported
+ - 9.3.8 Text knockout not implemented
+ - 9.5 Some type of fonts not supported yet (CIDFont, some others)
+ - 9.6.2.1 Missing width is not used for missing characters
+ - 9.6.4 d1 operator incorrectly doesn't ignore color/alpha operators
+ - 9.7.4 CIDSystemInfo ignored in Table 115
+
+Section 10: Issues
+ - Color management system is used for color conversions. This can
+ be turned of, and in that case, methods from 10.4.2 are used.
+ Undercolor removal and black generation are not used.
+ - 10.6 Halftoning is not implemented
+ - 10.7.2 Flatness is ignored
+ - 10.7.3 Smoothness is ignored
+ - 10.7.5 Automatic stroke adjustment is ignored
+ - 10.8 Separations are not produced
+ - 10.8.3 Separation simulation is not performed
+
+Section 11: Implemented partially
+ - Transparency is not implemented in regular Qt's painter,
+ but separate transparency renderer exist, which can render
+ also spot colors
+
+Section 12: Issues
+ - 12.3.2.2 Destinations are used only to leap on specified page,
+ position on page or fit hints are ignored
+ - 12.3.5.2 File collection folders are ignored, files are
+ displayed in a single list
+ - 12.3.6 Navigator for file collections is ignored
+ - 12.4.2 Page indices are used instead of labels
+ - 12.4.4 Presentations are not implemented
+ - 12.5.5 Annotation's transparency group is ignored
+ - 12.5.6.3 Annotation's states are not implemented in viewer
+ - 12.5.6.22 Watermark annotation - matrix and fixed print entry is not used
+ - 12.6.3 Some trigger events are not executed or not implemented
+ - 12.6.4 Some action are not executed in viewer
+ - 12.6.4.8 URI actions doesn't use IsMap
+ - 12.7.4.3 Variable text is implemented by Qt's QTextLayout
+ and drawing, pdf's specific default appearance strings,
+ and rich text is not implemented. This doesn't conform
+ to PDF specification, but all unicode characters can be used.
+ - 12.7.5.5 Signature field locking not implemented and signature
+ seed dictionary is ignored
+ - 12.7.6.2 Sumbit form action not implemented in viewer
+ - 12.7.6.4 Import data action not implemented in viewer
+ - 12.7.8 Form data format not implemented
+ - 12.8 Modification detection using UR3/DocMDP method is not
+ used, if signature is not valid, then it is not checked for
+ modifications
+ - 12.8 OCSP (Online Certificate Status Protocol) is not performed
+ - 12.8.4 Long term validation of signatures not performed
+ - 12.8.4.5 Validation data in custom VRI are not used, instead of them,
+ validation data in DSS or embedded in the signature are used
+ - 12.8.5 Document timestamp dictionary not implemented
+ - 12.8.6 Permissions not implemented
+ - 12.9 Measure feature not implemented
+ - 12.10 Geospatial features not implemented
+
+Section 13: Not implemented
+ - Multimedia features not implemented (except some classes, which
+ can read the data for multimedia - movies, sounds...)
+
+Section 14: Issues
+ - 14.3 Document metadata stream is not processed
+ - 14.4 Modifiable file identifier is not updated
+ - 14.5 Page-piece dictionaries not implemented
+ - 14.9 Accessibility support not implemented
+ - 14.10 Web capture not implemented
+ - 14.11 Prepress support not implemented at all, only
+ basic functionality works (media box, crop box, or,
+ for example, reading output intents)
+ - 14.12 Document parts not implemented
+
+Annex F: Not implemented
+ - Linearized PDF not implemented
diff --git a/Pdf4Qt.pro b/Pdf4Qt.pro
index 3c26213..82a13a3 100644
--- a/Pdf4Qt.pro
+++ b/Pdf4Qt.pro
@@ -1,42 +1,42 @@
-# Copyright (C) 2018-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 .
-
-TEMPLATE = subdirs
-
-SUBDIRS += \
- Pdf4QtLib \
- CodeGenerator \
- JBIG2_Viewer \
- PdfExampleGenerator \
- PdfTool \
- UnitTests \
- Pdf4QtViewer \
- Pdf4QtViewerPlugins \
- Pdf4QtViewerProfi \
- Pdf4QtViewerLite \
- Pdf4QtDocPageOrganizer
-
-CodeGenerator.depends = Pdf4QtLib
-JBIG2_Viewer.depends = Pdf4QtLib
-PdfExampleGenerator.depends = Pdf4QtLib
-PdfTool.depends = Pdf4QtLib
-UnitTests.depends = Pdf4QtLib
-Pdf4QtViewer.depends = Pdf4QtLib
-Pdf4QtViewerPlugins.depends = Pdf4QtLib
-Pdf4QtViewerProfi.depends = Pdf4QtViewer
-Pdf4QtViewerLite.depends = Pdf4QtViewer
-Pdf4QtDocPageOrganizer.depends = Pdf4QtLib
+# Copyright (C) 2018-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 .
+
+TEMPLATE = subdirs
+
+SUBDIRS += \
+ Pdf4QtLib \
+ CodeGenerator \
+ JBIG2_Viewer \
+ PdfExampleGenerator \
+ PdfTool \
+ UnitTests \
+ Pdf4QtViewer \
+ Pdf4QtViewerPlugins \
+ Pdf4QtViewerProfi \
+ Pdf4QtViewerLite \
+ Pdf4QtDocPageOrganizer
+
+CodeGenerator.depends = Pdf4QtLib
+JBIG2_Viewer.depends = Pdf4QtLib
+PdfExampleGenerator.depends = Pdf4QtLib
+PdfTool.depends = Pdf4QtLib
+UnitTests.depends = Pdf4QtLib
+Pdf4QtViewer.depends = Pdf4QtLib
+Pdf4QtViewerPlugins.depends = Pdf4QtLib
+Pdf4QtViewerProfi.depends = Pdf4QtViewer
+Pdf4QtViewerLite.depends = Pdf4QtViewer
+Pdf4QtDocPageOrganizer.depends = Pdf4QtLib
diff --git a/Pdf4QtDocPageOrganizer/Pdf4QtDocPageOrganizer.pro b/Pdf4QtDocPageOrganizer/Pdf4QtDocPageOrganizer.pro
index d9803c4..a0dcc94 100644
--- a/Pdf4QtDocPageOrganizer/Pdf4QtDocPageOrganizer.pro
+++ b/Pdf4QtDocPageOrganizer/Pdf4QtDocPageOrganizer.pro
@@ -1,68 +1,68 @@
-# 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 .
-
-QT += core gui widgets winextras
-
-TARGET = Pdf4QtDocPageOrganizer
-TEMPLATE = app
-
-VERSION = 1.0.0
-
-RC_ICONS = $$PWD/app-icon.ico
-
-QMAKE_TARGET_DESCRIPTION = "PDF Document Page Organizer"
-QMAKE_TARGET_COPYRIGHT = "(c) Jakub Melka 2018-2021"
-
-DEFINES += QT_DEPRECATED_WARNINGS
-QMAKE_CXXFLAGS += /std:c++latest /utf-8
-
-INCLUDEPATH += $$PWD/../PDF4QtLib/Sources
-DESTDIR = $$OUT_PWD/..
-LIBS += -L$$OUT_PWD/..
-LIBS += -lPDF4QtLib
-CONFIG += force_debug_info no_check_exist
-
-application.files = $$DESTDIR/Pdf4QtDocPageOrganizer.exe
-application.path = $$DESTDIR/install
-application.CONFIG += no_check_exist
-INSTALLS += application
-
-SOURCES += \
- aboutdialog.cpp \
- assembleoutputsettingsdialog.cpp \
- main.cpp \
- mainwindow.cpp \
- pageitemdelegate.cpp \
- pageitemmodel.cpp \
- selectbookmarkstoregroupdialog.cpp
-
-FORMS += \
- aboutdialog.ui \
- assembleoutputsettingsdialog.ui \
- mainwindow.ui \
- selectbookmarkstoregroupdialog.ui
-
-HEADERS += \
- aboutdialog.h \
- assembleoutputsettingsdialog.h \
- mainwindow.h \
- pageitemdelegate.h \
- pageitemmodel.h \
- selectbookmarkstoregroupdialog.h
-
-RESOURCES += \
- resources.qrc
+# 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 .
+
+QT += core gui widgets winextras
+
+TARGET = Pdf4QtDocPageOrganizer
+TEMPLATE = app
+
+VERSION = 1.0.0
+
+RC_ICONS = $$PWD/app-icon.ico
+
+QMAKE_TARGET_DESCRIPTION = "PDF Document Page Organizer"
+QMAKE_TARGET_COPYRIGHT = "(c) Jakub Melka 2018-2021"
+
+DEFINES += QT_DEPRECATED_WARNINGS
+QMAKE_CXXFLAGS += /std:c++latest /utf-8
+
+INCLUDEPATH += $$PWD/../PDF4QtLib/Sources
+DESTDIR = $$OUT_PWD/..
+LIBS += -L$$OUT_PWD/..
+LIBS += -lPDF4QtLib
+CONFIG += force_debug_info no_check_exist
+
+application.files = $$DESTDIR/Pdf4QtDocPageOrganizer.exe
+application.path = $$DESTDIR/install
+application.CONFIG += no_check_exist
+INSTALLS += application
+
+SOURCES += \
+ aboutdialog.cpp \
+ assembleoutputsettingsdialog.cpp \
+ main.cpp \
+ mainwindow.cpp \
+ pageitemdelegate.cpp \
+ pageitemmodel.cpp \
+ selectbookmarkstoregroupdialog.cpp
+
+FORMS += \
+ aboutdialog.ui \
+ assembleoutputsettingsdialog.ui \
+ mainwindow.ui \
+ selectbookmarkstoregroupdialog.ui
+
+HEADERS += \
+ aboutdialog.h \
+ assembleoutputsettingsdialog.h \
+ mainwindow.h \
+ pageitemdelegate.h \
+ pageitemmodel.h \
+ selectbookmarkstoregroupdialog.h
+
+RESOURCES += \
+ resources.qrc
diff --git a/Pdf4QtDocPageOrganizer/aboutdialog.cpp b/Pdf4QtDocPageOrganizer/aboutdialog.cpp
index 56a4f64..db4b411 100644
--- a/Pdf4QtDocPageOrganizer/aboutdialog.cpp
+++ b/Pdf4QtDocPageOrganizer/aboutdialog.cpp
@@ -1,64 +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 .
-
-#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", QApplication::applicationDisplayName());
- ui->copyrightLabel->setText(html);
-
- std::vector infos = pdf::PDFDependentLibraryInfo::getLibraryInfo();
-
- ui->tableWidget->setColumnCount(4);
- ui->tableWidget->setRowCount(static_cast(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
+// 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 .
+
+#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", QApplication::applicationDisplayName());
+ ui->copyrightLabel->setText(html);
+
+ std::vector infos = pdf::PDFDependentLibraryInfo::getLibraryInfo();
+
+ ui->tableWidget->setColumnCount(4);
+ ui->tableWidget->setRowCount(static_cast(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
diff --git a/Pdf4QtDocPageOrganizer/aboutdialog.h b/Pdf4QtDocPageOrganizer/aboutdialog.h
index b59fd91..4776270 100644
--- a/Pdf4QtDocPageOrganizer/aboutdialog.h
+++ b/Pdf4QtDocPageOrganizer/aboutdialog.h
@@ -1,45 +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 .
-
-#ifndef PDFDOCPAGEORGANIZER_PDFABOUTDIALOG_H
-#define PDFDOCPAGEORGANIZER_PDFABOUTDIALOG_H
-
-#include
-
-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
+// 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 .
+
+#ifndef PDFDOCPAGEORGANIZER_PDFABOUTDIALOG_H
+#define PDFDOCPAGEORGANIZER_PDFABOUTDIALOG_H
+
+#include
+
+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
diff --git a/Pdf4QtDocPageOrganizer/aboutdialog.ui b/Pdf4QtDocPageOrganizer/aboutdialog.ui
index 7c9489e..8cef7a9 100644
--- a/Pdf4QtDocPageOrganizer/aboutdialog.ui
+++ b/Pdf4QtDocPageOrganizer/aboutdialog.ui
@@ -1,269 +1,269 @@
-
-
- PDFAboutDialog
-
-
-
- 0
- 0
- 900
- 600
-
-
-
-
- 900
- 600
-
-
-
- About
-
-
- -
-
-
- <html><head/><body><p><span style=" font-weight:600;">PdfForQtViewer</span></p><p>Copyright 2018-2021 Jakub Melka. All rights reserved.</p><p>THE SOFTWARE IS PROVIDED "AS IS", 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.</p></body></html>
-
-
- true
-
-
-
- -
-
-
- true
-
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.875pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> GNU LESSER GENERAL PUBLIC LICENSE</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Version 3, 29 June 2007</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Everyone is permitted to copy and distribute verbatim copies</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> of this license document, but changing it is not allowed.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> This version of the GNU Lesser General Public License incorporates</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the terms and conditions of version 3 of the GNU General Public</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">License, supplemented by the additional permissions listed below.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 0. Additional Definitions.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> As used herein, "this License" refers to version 3 of the GNU Lesser</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">General Public License, and the "GNU GPL" refers to version 3 of the GNU</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">General Public License.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> "The Library" refers to a covered work governed by this License,</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">other than an Application or a Combined Work as defined below.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> An "Application" is any work that makes use of an interface provided</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">by the Library, but which is not otherwise based on the Library.</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Defining a subclass of a class defined by the Library is deemed a mode</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of using an interface provided by the Library.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> A "Combined Work" is a work produced by combining or linking an</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application with the Library. The particular version of the Library</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with which the Combined Work was made is also called the "Linked</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Version".</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> The "Minimal Corresponding Source" for a Combined Work means the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Corresponding Source for the Combined Work, excluding any source code</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">for portions of the Combined Work that, considered in isolation, are</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">based on the Application, and not on the Linked Version.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> The "Corresponding Application Code" for a Combined Work means the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">object code and/or source code for the Application, including any data</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and utility programs needed for reproducing the Combined Work from the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application, but excluding the System Libraries of the Combined Work.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 1. Exception to Section 3 of the GNU GPL.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> You may convey a covered work under sections 3 and 4 of this License</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">without being bound by section 3 of the GNU GPL.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 2. Conveying Modified Versions.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> If you modify a copy of the Library, and, in your modifications, a</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">facility refers to a function or data to be supplied by an Application</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">that uses the facility (other than as an argument passed when the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">facility is invoked), then you may convey a copy of the modified</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">version:</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a) under this License, provided that you make a good faith effort to</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> ensure that, in the event an Application does not supply the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> function or data, the facility still operates, and performs</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> whatever part of its purpose remains meaningful, or</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> b) under the GNU GPL, with none of the additional permissions of</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> this License applicable to that copy.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 3. Object Code Incorporating Material from Library Header Files.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> The object code form of an Application may incorporate material from</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a header file that is part of the Library. You may convey such object</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">code under terms of your choice, provided that, if the incorporated</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">material is not limited to numerical parameters, data structure</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">layouts and accessors, or small macros, inline functions and templates</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(ten or fewer lines in length), you do both of the following:</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a) Give prominent notice with each copy of the object code that the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Library is used in it and that the Library and its use are</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> covered by this License.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> b) Accompany the object code with a copy of the GNU GPL and this license</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> document.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 4. Combined Works.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> You may convey a Combined Work under terms of your choice that,</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">taken together, effectively do not restrict modification of the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">portions of the Library contained in the Combined Work and reverse</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">engineering for debugging such modifications, if you also do each of</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the following:</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a) Give prominent notice with each copy of the Combined Work that</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> the Library is used in it and that the Library and its use are</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> covered by this License.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> b) Accompany the Combined Work with a copy of the GNU GPL and this license</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> document.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> c) For a Combined Work that displays copyright notices during</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> execution, include the copyright notice for the Library among</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> these notices, as well as a reference directing the user to the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> copies of the GNU GPL and this license document.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> d) Do one of the following:</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 0) Convey the Minimal Corresponding Source under the terms of this</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> License, and the Corresponding Application Code in a form</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> suitable for, and under terms that permit, the user to</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> recombine or relink the Application with a modified version of</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> the Linked Version to produce a modified Combined Work, in the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> manner specified by section 6 of the GNU GPL for conveying</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Corresponding Source.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 1) Use a suitable shared library mechanism for linking with the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Library. A suitable mechanism is one that (a) uses at run time</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a copy of the Library already present on the user's computer</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> system, and (b) will operate properly with a modified version</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> of the Library that is interface-compatible with the Linked</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Version.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> e) Provide Installation Information, but only if you would otherwise</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> be required to provide such information under section 6 of the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> GNU GPL, and only to the extent that such information is</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> necessary to install and execute a modified version of the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Combined Work produced by recombining or relinking the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Application with a modified version of the Linked Version. (If</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> you use option 4d0, the Installation Information must accompany</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> the Minimal Corresponding Source and Corresponding Application</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Code. If you use option 4d1, you must provide the Installation</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Information in the manner specified by section 6 of the GNU GPL</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> for conveying Corresponding Source.)</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 5. Combined Libraries.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> You may place library facilities that are a work based on the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Library side by side in a single library together with other library</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">facilities that are not Applications and are not covered by this</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">License, and convey such a combined library under terms of your</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">choice, if you do both of the following:</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a) Accompany the combined library with a copy of the same work based</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> on the Library, uncombined with any other library facilities,</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> conveyed under the terms of this License.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> b) Give prominent notice with the combined library that part of it</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> is a work based on the Library, and explaining where to find the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> accompanying uncombined form of the same work.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 6. Revised Versions of the GNU Lesser General Public License.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> The Free Software Foundation may publish revised and/or new versions</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of the GNU Lesser General Public License from time to time. Such new</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">versions will be similar in spirit to the present version, but may</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">differ in detail to address new problems or concerns.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Each version is given a distinguishing version number. If the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Library as you received it specifies that a certain numbered version</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of the GNU Lesser General Public License "or any later version"</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">applies to it, you have the option of following the terms and</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">conditions either of that published version or of any later version</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">published by the Free Software Foundation. If the Library as you</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">received it does not specify a version number of the GNU Lesser</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">General Public License, you may choose any version of the GNU Lesser</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">General Public License ever published by the Free Software Foundation.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> If the Library as you received it specifies that a proxy can decide</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">whether future versions of the GNU Lesser General Public License shall</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">apply, that proxy's public statement of acceptance of any version is</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">permanent authorization for you to choose that version for the</p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Library.</p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>
-
-
-
- -
-
-
- Used libraries
-
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Ok
-
-
-
-
-
-
-
-
- buttonBox
- accepted()
- PDFAboutDialog
- accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- PDFAboutDialog
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
-
+
+
+ PDFAboutDialog
+
+
+
+ 0
+ 0
+ 900
+ 600
+
+
+
+
+ 900
+ 600
+
+
+
+ About
+
+
+ -
+
+
+ <html><head/><body><p><span style=" font-weight:600;">PdfForQtViewer</span></p><p>Copyright 2018-2021 Jakub Melka. All rights reserved.</p><p>THE SOFTWARE IS PROVIDED "AS IS", 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.</p></body></html>
+
+
+ true
+
+
+
+ -
+
+
+ true
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.875pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> GNU LESSER GENERAL PUBLIC LICENSE</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Version 3, 29 June 2007</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Everyone is permitted to copy and distribute verbatim copies</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> of this license document, but changing it is not allowed.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> This version of the GNU Lesser General Public License incorporates</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the terms and conditions of version 3 of the GNU General Public</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">License, supplemented by the additional permissions listed below.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 0. Additional Definitions.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> As used herein, "this License" refers to version 3 of the GNU Lesser</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">General Public License, and the "GNU GPL" refers to version 3 of the GNU</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">General Public License.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> "The Library" refers to a covered work governed by this License,</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">other than an Application or a Combined Work as defined below.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> An "Application" is any work that makes use of an interface provided</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">by the Library, but which is not otherwise based on the Library.</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Defining a subclass of a class defined by the Library is deemed a mode</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of using an interface provided by the Library.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> A "Combined Work" is a work produced by combining or linking an</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application with the Library. The particular version of the Library</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with which the Combined Work was made is also called the "Linked</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Version".</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> The "Minimal Corresponding Source" for a Combined Work means the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Corresponding Source for the Combined Work, excluding any source code</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">for portions of the Combined Work that, considered in isolation, are</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">based on the Application, and not on the Linked Version.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> The "Corresponding Application Code" for a Combined Work means the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">object code and/or source code for the Application, including any data</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and utility programs needed for reproducing the Combined Work from the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application, but excluding the System Libraries of the Combined Work.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 1. Exception to Section 3 of the GNU GPL.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> You may convey a covered work under sections 3 and 4 of this License</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">without being bound by section 3 of the GNU GPL.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 2. Conveying Modified Versions.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> If you modify a copy of the Library, and, in your modifications, a</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">facility refers to a function or data to be supplied by an Application</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">that uses the facility (other than as an argument passed when the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">facility is invoked), then you may convey a copy of the modified</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">version:</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a) under this License, provided that you make a good faith effort to</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> ensure that, in the event an Application does not supply the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> function or data, the facility still operates, and performs</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> whatever part of its purpose remains meaningful, or</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> b) under the GNU GPL, with none of the additional permissions of</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> this License applicable to that copy.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 3. Object Code Incorporating Material from Library Header Files.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> The object code form of an Application may incorporate material from</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a header file that is part of the Library. You may convey such object</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">code under terms of your choice, provided that, if the incorporated</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">material is not limited to numerical parameters, data structure</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">layouts and accessors, or small macros, inline functions and templates</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(ten or fewer lines in length), you do both of the following:</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a) Give prominent notice with each copy of the object code that the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Library is used in it and that the Library and its use are</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> covered by this License.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> b) Accompany the object code with a copy of the GNU GPL and this license</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> document.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 4. Combined Works.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> You may convey a Combined Work under terms of your choice that,</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">taken together, effectively do not restrict modification of the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">portions of the Library contained in the Combined Work and reverse</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">engineering for debugging such modifications, if you also do each of</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the following:</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a) Give prominent notice with each copy of the Combined Work that</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> the Library is used in it and that the Library and its use are</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> covered by this License.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> b) Accompany the Combined Work with a copy of the GNU GPL and this license</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> document.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> c) For a Combined Work that displays copyright notices during</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> execution, include the copyright notice for the Library among</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> these notices, as well as a reference directing the user to the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> copies of the GNU GPL and this license document.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> d) Do one of the following:</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 0) Convey the Minimal Corresponding Source under the terms of this</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> License, and the Corresponding Application Code in a form</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> suitable for, and under terms that permit, the user to</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> recombine or relink the Application with a modified version of</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> the Linked Version to produce a modified Combined Work, in the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> manner specified by section 6 of the GNU GPL for conveying</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Corresponding Source.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 1) Use a suitable shared library mechanism for linking with the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Library. A suitable mechanism is one that (a) uses at run time</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a copy of the Library already present on the user's computer</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> system, and (b) will operate properly with a modified version</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> of the Library that is interface-compatible with the Linked</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Version.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> e) Provide Installation Information, but only if you would otherwise</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> be required to provide such information under section 6 of the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> GNU GPL, and only to the extent that such information is</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> necessary to install and execute a modified version of the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Combined Work produced by recombining or relinking the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Application with a modified version of the Linked Version. (If</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> you use option 4d0, the Installation Information must accompany</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> the Minimal Corresponding Source and Corresponding Application</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Code. If you use option 4d1, you must provide the Installation</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Information in the manner specified by section 6 of the GNU GPL</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> for conveying Corresponding Source.)</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 5. Combined Libraries.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> You may place library facilities that are a work based on the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Library side by side in a single library together with other library</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">facilities that are not Applications and are not covered by this</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">License, and convey such a combined library under terms of your</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">choice, if you do both of the following:</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> a) Accompany the combined library with a copy of the same work based</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> on the Library, uncombined with any other library facilities,</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> conveyed under the terms of this License.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> b) Give prominent notice with the combined library that part of it</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> is a work based on the Library, and explaining where to find the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> accompanying uncombined form of the same work.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 6. Revised Versions of the GNU Lesser General Public License.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> The Free Software Foundation may publish revised and/or new versions</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of the GNU Lesser General Public License from time to time. Such new</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">versions will be similar in spirit to the present version, but may</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">differ in detail to address new problems or concerns.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> Each version is given a distinguishing version number. If the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Library as you received it specifies that a certain numbered version</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of the GNU Lesser General Public License "or any later version"</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">applies to it, you have the option of following the terms and</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">conditions either of that published version or of any later version</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">published by the Free Software Foundation. If the Library as you</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">received it does not specify a version number of the GNU Lesser</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">General Public License, you may choose any version of the GNU Lesser</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">General Public License ever published by the Free Software Foundation.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> If the Library as you received it specifies that a proxy can decide</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">whether future versions of the GNU Lesser General Public License shall</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">apply, that proxy's public statement of acceptance of any version is</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">permanent authorization for you to choose that version for the</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Library.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>
+
+
+
+ -
+
+
+ Used libraries
+
+
+
+ -
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ PDFAboutDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ PDFAboutDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.cpp b/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.cpp
index fc3f63b..5a82e63 100644
--- a/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.cpp
+++ b/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.cpp
@@ -1,78 +1,78 @@
-// 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 .
-
-#include "assembleoutputsettingsdialog.h"
-#include "ui_assembleoutputsettingsdialog.h"
-
-#include "pdfwidgetutils.h"
-
-#include
-
-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
+// 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 .
+
+#include "assembleoutputsettingsdialog.h"
+#include "ui_assembleoutputsettingsdialog.h"
+
+#include "pdfwidgetutils.h"
+
+#include
+
+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
diff --git a/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.h b/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.h
index 18140c7..0594b3a 100644
--- a/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.h
+++ b/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.h
@@ -1,55 +1,55 @@
-// 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 .
-
-#ifndef PDFDOCPAGEORGANIZER_ASSEMBLEOUTPUTSETTINGSDIALOG_H
-#define PDFDOCPAGEORGANIZER_ASSEMBLEOUTPUTSETTINGSDIALOG_H
-
-#include "pdfdocumentmanipulator.h"
-
-#include
-
-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
+// 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 .
+
+#ifndef PDFDOCPAGEORGANIZER_ASSEMBLEOUTPUTSETTINGSDIALOG_H
+#define PDFDOCPAGEORGANIZER_ASSEMBLEOUTPUTSETTINGSDIALOG_H
+
+#include "pdfdocumentmanipulator.h"
+
+#include
+
+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
diff --git a/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.ui b/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.ui
index 72f5fcf..72ffcf7 100644
--- a/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.ui
+++ b/Pdf4QtDocPageOrganizer/assembleoutputsettingsdialog.ui
@@ -1,131 +1,131 @@
-
-
- AssembleOutputSettingsDialog
-
-
-
- 0
- 0
- 614
- 250
-
-
-
- Assemble Documents
-
-
- -
-
-
- Assemble Documents
-
-
-
-
-
-
- ...
-
-
-
- -
-
-
- -
-
-
- File template
-
-
-
- -
-
-
- <html><head/><body><p>In a template file name, you can use symbols '#' for output document number (means output document index, not input document) or '@' for page number of input document (if document contains more pages, it is a page number of a original document), or '%' for index of input document. Use more '#' or '@' or '%' for setting minimal number of digits (if number has less digits, the they are padded with zero).</p></body></html>
-
-
- true
-
-
-
- -
-
-
- Overwrite existing files
-
-
-
- -
-
-
- doc-#.pdf
-
-
-
- -
-
-
- Generate into directory
-
-
-
- -
-
-
- Outline Mode
-
-
-
- -
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
-
-
- buttonBox
- accepted()
- AssembleOutputSettingsDialog
- accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- AssembleOutputSettingsDialog
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
-
+
+
+ AssembleOutputSettingsDialog
+
+
+
+ 0
+ 0
+ 614
+ 250
+
+
+
+ Assemble Documents
+
+
+ -
+
+
+ Assemble Documents
+
+
+
-
+
+
+ ...
+
+
+
+ -
+
+
+ -
+
+
+ File template
+
+
+
+ -
+
+
+ <html><head/><body><p>In a template file name, you can use symbols '#' for output document number (means output document index, not input document) or '@' for page number of input document (if document contains more pages, it is a page number of a original document), or '%' for index of input document. Use more '#' or '@' or '%' for setting minimal number of digits (if number has less digits, the they are padded with zero).</p></body></html>
+
+
+ true
+
+
+
+ -
+
+
+ Overwrite existing files
+
+
+
+ -
+
+
+ doc-#.pdf
+
+
+
+ -
+
+
+ Generate into directory
+
+
+
+ -
+
+
+ Outline Mode
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ AssembleOutputSettingsDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ AssembleOutputSettingsDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/Pdf4QtDocPageOrganizer/main.cpp b/Pdf4QtDocPageOrganizer/main.cpp
index 996a0d9..1c740f0 100644
--- a/Pdf4QtDocPageOrganizer/main.cpp
+++ b/Pdf4QtDocPageOrganizer/main.cpp
@@ -1,46 +1,46 @@
-// 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 .
-
-#include "pdfconstants.h"
-#include "mainwindow.h"
-
-#include
-#include
-
-int main(int argc, char *argv[])
-{
- QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
- QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true);
- QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
- 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();
-}
+// 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 .
+
+#include "pdfconstants.h"
+#include "mainwindow.h"
+
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
+ QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true);
+ QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
+ 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();
+}
diff --git a/Pdf4QtDocPageOrganizer/mainwindow.cpp b/Pdf4QtDocPageOrganizer/mainwindow.cpp
index c2c5cb2..d18f830 100644
--- a/Pdf4QtDocPageOrganizer/mainwindow.cpp
+++ b/Pdf4QtDocPageOrganizer/mainwindow.cpp
@@ -1,872 +1,872 @@
-// 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 .
-
-#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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-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));
-
- QToolBar* mainToolbar = addToolBar(tr("Main"));
- mainToolbar->setObjectName("main_toolbar");
- mainToolbar->addAction(ui->actionAddDocument);
- 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();
- for (QToolBar* toolbar : toolbars)
- {
- toolbar->setIconSize(iconSize);
- ui->menuToolbars->addAction(toolbar->toggleViewAction());
- }
-
- connect(&m_mapper, QOverload::of(&QSignalMapper::mapped), this, &MainWindow::onMappedActionTriggered);
- connect(ui->documentItemsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::updateActions);
-
- QList actions = findChildren();
- 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_actionAddDocument_triggered()
-{
- QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)"));
- if (!fileName.isEmpty())
- {
- insertDocument(fileName, QModelIndex());
- }
-}
-
-void MainWindow::onMappedActionTriggered(int actionId)
-{
- performOperation(static_cast(actionId));
-}
-
-void MainWindow::updateActions()
-{
- QList actions = findChildren();
- for (QAction* action : actions)
- {
- QVariant actionData = action->data();
- if (actionData.isValid())
- {
- action->setEnabled(canPerformOperation(static_cast(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::desktop()->availableGeometry(this);
- 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();
-}
-
-void MainWindow::insertDocument(const QString& fileName, const QModelIndex& insertIndex)
-{
- 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)
- {
- 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
- {
- QMessageBox::critical(this, tr("Error"), tr("Document security doesn't permit to organize pages."));
- }
- }
- else if (result == pdf::PDFDocumentReader::Result::Failed)
- {
- QMessageBox::critical(this, tr("Error"), errorMessage);
- }
-
- updateActions();
-}
-
-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:
- 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::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> 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> 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& 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 result = writer.write(filename, document, isDocumentFileAlreadyExisting);
-
- if (!result)
- {
- QMessageBox::critical(this, tr("Error"), result.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(" *."));
- QString fileName = QFileDialog::getOpenFileName(this, tr("Select Image"), m_settings.directory, filter, nullptr);
-
- if (!fileName.isEmpty())
- {
- QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
- m_model->insertImage(fileName, !indexes.isEmpty() ? indexes.front() : QModelIndex());
- }
- break;
- }
-
- case Operation::InsertPDF:
- {
- QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
- QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)"));
- if (!fileName.isEmpty())
- {
- insertDocument(fileName, !indexes.isEmpty() ? indexes.back() : QModelIndex());
- }
- 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();
-
- QModelIndex firstIndex = rootIndex.child(0, 0);
- QModelIndex lastIndex = rootIndex.child(rootIndex.model()->rowCount() - 1, 0);
- 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& 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 breakPageIndices;
- std::vector 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(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
+// 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 .
+
+#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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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));
+
+ QToolBar* mainToolbar = addToolBar(tr("Main"));
+ mainToolbar->setObjectName("main_toolbar");
+ mainToolbar->addAction(ui->actionAddDocument);
+ 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();
+ for (QToolBar* toolbar : toolbars)
+ {
+ toolbar->setIconSize(iconSize);
+ ui->menuToolbars->addAction(toolbar->toggleViewAction());
+ }
+
+ connect(&m_mapper, QOverload::of(&QSignalMapper::mapped), this, &MainWindow::onMappedActionTriggered);
+ connect(ui->documentItemsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::updateActions);
+
+ QList actions = findChildren();
+ 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_actionAddDocument_triggered()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)"));
+ if (!fileName.isEmpty())
+ {
+ insertDocument(fileName, QModelIndex());
+ }
+}
+
+void MainWindow::onMappedActionTriggered(int actionId)
+{
+ performOperation(static_cast(actionId));
+}
+
+void MainWindow::updateActions()
+{
+ QList actions = findChildren();
+ for (QAction* action : actions)
+ {
+ QVariant actionData = action->data();
+ if (actionData.isValid())
+ {
+ action->setEnabled(canPerformOperation(static_cast(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::desktop()->availableGeometry(this);
+ 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();
+}
+
+void MainWindow::insertDocument(const QString& fileName, const QModelIndex& insertIndex)
+{
+ 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)
+ {
+ 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
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Document security doesn't permit to organize pages."));
+ }
+ }
+ else if (result == pdf::PDFDocumentReader::Result::Failed)
+ {
+ QMessageBox::critical(this, tr("Error"), errorMessage);
+ }
+
+ updateActions();
+}
+
+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:
+ 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::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> 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> 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& 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 result = writer.write(filename, document, isDocumentFileAlreadyExisting);
+
+ if (!result)
+ {
+ QMessageBox::critical(this, tr("Error"), result.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(" *."));
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select Image"), m_settings.directory, filter, nullptr);
+
+ if (!fileName.isEmpty())
+ {
+ QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
+ m_model->insertImage(fileName, !indexes.isEmpty() ? indexes.front() : QModelIndex());
+ }
+ break;
+ }
+
+ case Operation::InsertPDF:
+ {
+ QModelIndexList indexes = ui->documentItemsView->selectionModel()->selection().indexes();
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)"));
+ if (!fileName.isEmpty())
+ {
+ insertDocument(fileName, !indexes.isEmpty() ? indexes.back() : QModelIndex());
+ }
+ 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();
+
+ QModelIndex firstIndex = rootIndex.child(0, 0);
+ QModelIndex lastIndex = rootIndex.child(rootIndex.model()->rowCount() - 1, 0);
+ 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& 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 breakPageIndices;
+ std::vector 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(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
diff --git a/Pdf4QtDocPageOrganizer/mainwindow.h b/Pdf4QtDocPageOrganizer/mainwindow.h
index 9130fef..40cea6f 100644
--- a/Pdf4QtDocPageOrganizer/mainwindow.h
+++ b/Pdf4QtDocPageOrganizer/mainwindow.h
@@ -1,128 +1,128 @@
-// 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 .
-
-#ifndef PDFDOCPAGEORGANIZER_MAINWINDOW_H
-#define PDFDOCPAGEORGANIZER_MAINWINDOW_H
-
-#include
-
-#include "pageitemmodel.h"
-#include "pageitemdelegate.h"
-
-#include
-
-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
- };
-
-private slots:
- void on_actionClose_triggered();
- void on_actionAddDocument_triggered();
- void onMappedActionTriggered(int actionId);
- void updateActions();
-
-private:
- void loadSettings();
- void saveSettings();
- void insertDocument(const QString& fileName, const QModelIndex& insertIndex);
-
- bool canPerformOperation(Operation operation) const;
- void performOperation(Operation operation);
-
- struct Settings
- {
- QString directory;
- };
-
- Ui::MainWindow* ui;
-
- PageItemModel* m_model;
- PageItemDelegate* m_delegate;
- Settings m_settings;
- QSignalMapper m_mapper;
- Qt::DropAction m_dropAction;
-};
-
-} // namespace pdfdocpage
-
-#endif // PDFDOCPAGEORGANIZER_MAINWINDOW_H
+// 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 .
+
+#ifndef PDFDOCPAGEORGANIZER_MAINWINDOW_H
+#define PDFDOCPAGEORGANIZER_MAINWINDOW_H
+
+#include
+
+#include "pageitemmodel.h"
+#include "pageitemdelegate.h"
+
+#include
+
+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
+ };
+
+private slots:
+ void on_actionClose_triggered();
+ void on_actionAddDocument_triggered();
+ void onMappedActionTriggered(int actionId);
+ void updateActions();
+
+private:
+ void loadSettings();
+ void saveSettings();
+ void insertDocument(const QString& fileName, const QModelIndex& insertIndex);
+
+ bool canPerformOperation(Operation operation) const;
+ void performOperation(Operation operation);
+
+ struct Settings
+ {
+ QString directory;
+ };
+
+ Ui::MainWindow* ui;
+
+ PageItemModel* m_model;
+ PageItemDelegate* m_delegate;
+ Settings m_settings;
+ QSignalMapper m_mapper;
+ Qt::DropAction m_dropAction;
+};
+
+} // namespace pdfdocpage
+
+#endif // PDFDOCPAGEORGANIZER_MAINWINDOW_H
diff --git a/Pdf4QtDocPageOrganizer/mainwindow.ui b/Pdf4QtDocPageOrganizer/mainwindow.ui
index 506c2eb..aed788c 100644
--- a/Pdf4QtDocPageOrganizer/mainwindow.ui
+++ b/Pdf4QtDocPageOrganizer/mainwindow.ui
@@ -1,590 +1,590 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 800
- 600
-
-
-
- Workspace
-
-
-
- -
-
-
- true
-
-
- QAbstractItemView::DragDrop
-
-
- Qt::MoveAction
-
-
- QAbstractItemView::ExtendedSelection
-
-
- QListView::LeftToRight
-
-
- QListView::IconMode
-
-
- Qt::AlignCenter
-
-
-
-
-
-
-
-
-
-
- :/pdfdocpage/resources/open.svg:/pdfdocpage/resources/open.svg
-
-
- Add Document
-
-
- Ctrl+O
-
-
-
-
-
- :/pdfdocpage/resources/close.svg:/pdfdocpage/resources/close.svg
-
-
- Close
-
-
- Alt+F4
-
-
-
-
-
- :/pdfdocpage/resources/clone-selection.svg:/pdfdocpage/resources/clone-selection.svg
-
-
- Clone Selection
-
-
- Ctrl+L
-
-
-
-
-
- :/pdfdocpage/resources/remove-selection.svg:/pdfdocpage/resources/remove-selection.svg
-
-
- Remove Selection
-
-
- Del
-
-
-
-
-
- :/pdfdocpage/resources/restore-removed-items.svg:/pdfdocpage/resources/restore-removed-items.svg
-
-
- Restore Removed Items
-
-
- Ctrl+Shift+R
-
-
-
-
-
- :/pdfdocpage/resources/insert-page-from-pdf.svg:/pdfdocpage/resources/insert-page-from-pdf.svg
-
-
- Insert PDF
-
-
- Insert PDF
-
-
- Ctrl+I
-
-
-
-
-
- :/pdfdocpage/resources/insert-image.svg:/pdfdocpage/resources/insert-image.svg
-
-
- Insert Image
-
-
- Ctrl+Alt+I
-
-
-
-
-
- :/pdfdocpage/resources/insert-empty-page.svg:/pdfdocpage/resources/insert-empty-page.svg
-
-
- Insert Empty Page
-
-
- Ctrl+Shift+I
-
-
-
-
-
- :/pdfdocpage/resources/cut.svg:/pdfdocpage/resources/cut.svg
-
-
- Cut
-
-
- Ctrl+X
-
-
-
-
-
- :/pdfdocpage/resources/copy.svg:/pdfdocpage/resources/copy.svg
-
-
- Copy
-
-
- Ctrl+C
-
-
-
-
-
- :/pdfdocpage/resources/paste.svg:/pdfdocpage/resources/paste.svg
-
-
- Paste
-
-
- Ctrl+V
-
-
-
-
-
- :/pdfdocpage/resources/replace-selection.svg:/pdfdocpage/resources/replace-selection.svg
-
-
- Replace Selection
-
-
- Ctrl+Alt+R
-
-
-
-
-
- :/pdfdocpage/resources/select-none.svg:/pdfdocpage/resources/select-none.svg
-
-
- Select None
-
-
- Ctrl+N
-
-
-
-
-
- :/pdfdocpage/resources/select-all.svg:/pdfdocpage/resources/select-all.svg
-
-
- Select All
-
-
- Ctrl+A
-
-
-
-
-
- :/pdfdocpage/resources/select-even.svg:/pdfdocpage/resources/select-even.svg
-
-
- Select Even
-
-
- F9
-
-
-
-
-
- :/pdfdocpage/resources/select-odd.svg:/pdfdocpage/resources/select-odd.svg
-
-
- Select Odd
-
-
- F10
-
-
-
-
-
- :/pdfdocpage/resources/select-portrait.svg:/pdfdocpage/resources/select-portrait.svg
-
-
- Select Portrait
-
-
- F11
-
-
-
-
-
- :/pdfdocpage/resources/select-landscape.svg:/pdfdocpage/resources/select-landscape.svg
-
-
- Select Landscape
-
-
- F12
-
-
-
-
-
- :/pdfdocpage/resources/rotate-right.svg:/pdfdocpage/resources/rotate-right.svg
-
-
- Rotate Right
-
-
- F4
-
-
-
-
-
- :/pdfdocpage/resources/rotate-left.svg:/pdfdocpage/resources/rotate-left.svg
-
-
- Rotate Left
-
-
- Shift+F4
-
-
-
-
-
- :/pdfdocpage/resources/zoom-in.svg:/pdfdocpage/resources/zoom-in.svg
-
-
- Zoom In
-
-
- Ctrl++
-
-
-
-
-
- :/pdfdocpage/resources/zoom-out.svg:/pdfdocpage/resources/zoom-out.svg
-
-
- Zoom Out
-
-
- Ctrl+-
-
-
-
-
-
- :/pdfdocpage/resources/get-source.svg:/pdfdocpage/resources/get-source.svg
-
-
- Get Source
-
-
-
-
-
- :/pdfdocpage/resources/about.svg:/pdfdocpage/resources/about.svg
-
-
- About
-
-
- F1
-
-
-
-
-
- :/pdfdocpage/resources/make-united-document.svg:/pdfdocpage/resources/make-united-document.svg
-
-
- United Document
-
-
- F5
-
-
-
-
-
- :/pdfdocpage/resources/make-separated-document.svg:/pdfdocpage/resources/make-separated-document.svg
-
-
- Separate to Multiple Documents
-
-
- F6
-
-
-
-
-
- :/pdfdocpage/resources/make-separated-document-from-groups.svg:/pdfdocpage/resources/make-separated-document-from-groups.svg
-
-
- Separate to Multiple Documents (Grouped)
-
-
- F7
-
-
-
-
-
- :/pdfdocpage/resources/group.svg:/pdfdocpage/resources/group.svg
-
-
- Group
-
-
- Ctrl+G
-
-
-
-
-
- :/pdfdocpage/resources/ungroup.svg:/pdfdocpage/resources/ungroup.svg
-
-
- Ungroup
-
-
- Ctrl+Shift+G
-
-
-
-
-
- :/pdfdocpage/resources/clear.svg:/pdfdocpage/resources/clear.svg
-
-
- Clear
-
-
- Ctrl+W
-
-
-
-
-
- :/pdfdocpage/resources/regroup-even-odd.svg:/pdfdocpage/resources/regroup-even-odd.svg
-
-
- Regroup by Even/Odd Pages
-
-
-
-
-
- :/pdfdocpage/resources/regroup-pairs.svg:/pdfdocpage/resources/regroup-pairs.svg
-
-
- Regroup by Page Pairs
-
-
-
-
-
- :/pdfdocpage/resources/regroup-bookmarks.svg:/pdfdocpage/resources/regroup-bookmarks.svg
-
-
- Regroup by Bookmarks
-
-
-
-
-
- :/pdfdocpage/resources/regroup-alternating.svg:/pdfdocpage/resources/regroup-alternating.svg
-
-
- Regroup by Alternating Pages
-
-
-
-
-
- :/pdfdocpage/resources/regroup-alternating-reversed.svg:/pdfdocpage/resources/regroup-alternating-reversed.svg
-
-
- Regroup by Alternating Pages (Reversed Order)
-
-
-
-
-
- :/pdfdocpage/resources/invert-selection.svg:/pdfdocpage/resources/invert-selection.svg
-
-
- Invert Selection
-
-
-
-
-
- :/pdfdocpage/resources/undo.svg:/pdfdocpage/resources/undo.svg
-
-
- Undo
-
-
- Ctrl+Z
-
-
-
-
-
- :/pdfdocpage/resources/redo.svg:/pdfdocpage/resources/redo.svg
-
-
- Redo
-
-
- Ctrl+Y
-
-
-
-
-
-
-
-
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 800
+ 600
+
+
+
+ Workspace
+
+
+
+ -
+
+
+ true
+
+
+ QAbstractItemView::DragDrop
+
+
+ Qt::MoveAction
+
+
+ QAbstractItemView::ExtendedSelection
+
+
+ QListView::LeftToRight
+
+
+ QListView::IconMode
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+
+
+ :/pdfdocpage/resources/open.svg:/pdfdocpage/resources/open.svg
+
+
+ Add Document
+
+
+ Ctrl+O
+
+
+
+
+
+ :/pdfdocpage/resources/close.svg:/pdfdocpage/resources/close.svg
+
+
+ Close
+
+
+ Alt+F4
+
+
+
+
+
+ :/pdfdocpage/resources/clone-selection.svg:/pdfdocpage/resources/clone-selection.svg
+
+
+ Clone Selection
+
+
+ Ctrl+L
+
+
+
+
+
+ :/pdfdocpage/resources/remove-selection.svg:/pdfdocpage/resources/remove-selection.svg
+
+
+ Remove Selection
+
+
+ Del
+
+
+
+
+
+ :/pdfdocpage/resources/restore-removed-items.svg:/pdfdocpage/resources/restore-removed-items.svg
+
+
+ Restore Removed Items
+
+
+ Ctrl+Shift+R
+
+
+
+
+
+ :/pdfdocpage/resources/insert-page-from-pdf.svg:/pdfdocpage/resources/insert-page-from-pdf.svg
+
+
+ Insert PDF
+
+
+ Insert PDF
+
+
+ Ctrl+I
+
+
+
+
+
+ :/pdfdocpage/resources/insert-image.svg:/pdfdocpage/resources/insert-image.svg
+
+
+ Insert Image
+
+
+ Ctrl+Alt+I
+
+
+
+
+
+ :/pdfdocpage/resources/insert-empty-page.svg:/pdfdocpage/resources/insert-empty-page.svg
+
+
+ Insert Empty Page
+
+
+ Ctrl+Shift+I
+
+
+
+
+
+ :/pdfdocpage/resources/cut.svg:/pdfdocpage/resources/cut.svg
+
+
+ Cut
+
+
+ Ctrl+X
+
+
+
+
+
+ :/pdfdocpage/resources/copy.svg:/pdfdocpage/resources/copy.svg
+
+
+ Copy
+
+
+ Ctrl+C
+
+
+
+
+
+ :/pdfdocpage/resources/paste.svg:/pdfdocpage/resources/paste.svg
+
+
+ Paste
+
+
+ Ctrl+V
+
+
+
+
+
+ :/pdfdocpage/resources/replace-selection.svg:/pdfdocpage/resources/replace-selection.svg
+
+
+ Replace Selection
+
+
+ Ctrl+Alt+R
+
+
+
+
+
+ :/pdfdocpage/resources/select-none.svg:/pdfdocpage/resources/select-none.svg
+
+
+ Select None
+
+
+ Ctrl+N
+
+
+
+
+
+ :/pdfdocpage/resources/select-all.svg:/pdfdocpage/resources/select-all.svg
+
+
+ Select All
+
+
+ Ctrl+A
+
+
+
+
+
+ :/pdfdocpage/resources/select-even.svg:/pdfdocpage/resources/select-even.svg
+
+
+ Select Even
+
+
+ F9
+
+
+
+
+
+ :/pdfdocpage/resources/select-odd.svg:/pdfdocpage/resources/select-odd.svg
+
+
+ Select Odd
+
+
+ F10
+
+
+
+
+
+ :/pdfdocpage/resources/select-portrait.svg:/pdfdocpage/resources/select-portrait.svg
+
+
+ Select Portrait
+
+
+ F11
+
+
+
+
+
+ :/pdfdocpage/resources/select-landscape.svg:/pdfdocpage/resources/select-landscape.svg
+
+
+ Select Landscape
+
+
+ F12
+
+
+
+
+
+ :/pdfdocpage/resources/rotate-right.svg:/pdfdocpage/resources/rotate-right.svg
+
+
+ Rotate Right
+
+
+ F4
+
+
+
+
+
+ :/pdfdocpage/resources/rotate-left.svg:/pdfdocpage/resources/rotate-left.svg
+
+
+ Rotate Left
+
+
+ Shift+F4
+
+
+
+
+
+ :/pdfdocpage/resources/zoom-in.svg:/pdfdocpage/resources/zoom-in.svg
+
+
+ Zoom In
+
+
+ Ctrl++
+
+
+
+
+
+ :/pdfdocpage/resources/zoom-out.svg:/pdfdocpage/resources/zoom-out.svg
+
+
+ Zoom Out
+
+
+ Ctrl+-
+
+
+
+
+
+ :/pdfdocpage/resources/get-source.svg:/pdfdocpage/resources/get-source.svg
+
+
+ Get Source
+
+
+
+
+
+ :/pdfdocpage/resources/about.svg:/pdfdocpage/resources/about.svg
+
+
+ About
+
+
+ F1
+
+
+
+
+
+ :/pdfdocpage/resources/make-united-document.svg:/pdfdocpage/resources/make-united-document.svg
+
+
+ United Document
+
+
+ F5
+
+
+
+
+
+ :/pdfdocpage/resources/make-separated-document.svg:/pdfdocpage/resources/make-separated-document.svg
+
+
+ Separate to Multiple Documents
+
+
+ F6
+
+
+
+
+
+ :/pdfdocpage/resources/make-separated-document-from-groups.svg:/pdfdocpage/resources/make-separated-document-from-groups.svg
+
+
+ Separate to Multiple Documents (Grouped)
+
+
+ F7
+
+
+
+
+
+ :/pdfdocpage/resources/group.svg:/pdfdocpage/resources/group.svg
+
+
+ Group
+
+
+ Ctrl+G
+
+
+
+
+
+ :/pdfdocpage/resources/ungroup.svg:/pdfdocpage/resources/ungroup.svg
+
+
+ Ungroup
+
+
+ Ctrl+Shift+G
+
+
+
+
+
+ :/pdfdocpage/resources/clear.svg:/pdfdocpage/resources/clear.svg
+
+
+ Clear
+
+
+ Ctrl+W
+
+
+
+
+
+ :/pdfdocpage/resources/regroup-even-odd.svg:/pdfdocpage/resources/regroup-even-odd.svg
+
+
+ Regroup by Even/Odd Pages
+
+
+
+
+
+ :/pdfdocpage/resources/regroup-pairs.svg:/pdfdocpage/resources/regroup-pairs.svg
+
+
+ Regroup by Page Pairs
+
+
+
+
+
+ :/pdfdocpage/resources/regroup-bookmarks.svg:/pdfdocpage/resources/regroup-bookmarks.svg
+
+
+ Regroup by Bookmarks
+
+
+
+
+
+ :/pdfdocpage/resources/regroup-alternating.svg:/pdfdocpage/resources/regroup-alternating.svg
+
+
+ Regroup by Alternating Pages
+
+
+
+
+
+ :/pdfdocpage/resources/regroup-alternating-reversed.svg:/pdfdocpage/resources/regroup-alternating-reversed.svg
+
+
+ Regroup by Alternating Pages (Reversed Order)
+
+
+
+
+
+ :/pdfdocpage/resources/invert-selection.svg:/pdfdocpage/resources/invert-selection.svg
+
+
+ Invert Selection
+
+
+
+
+
+ :/pdfdocpage/resources/undo.svg:/pdfdocpage/resources/undo.svg
+
+
+ Undo
+
+
+ Ctrl+Z
+
+
+
+
+
+ :/pdfdocpage/resources/redo.svg:/pdfdocpage/resources/redo.svg
+
+
+ Redo
+
+
+ Ctrl+Y
+
+
+
+
+
+
+
+
diff --git a/Pdf4QtDocPageOrganizer/pageitemdelegate.cpp b/Pdf4QtDocPageOrganizer/pageitemdelegate.cpp
index 60c75bd..e068620 100644
--- a/Pdf4QtDocPageOrganizer/pageitemdelegate.cpp
+++ b/Pdf4QtDocPageOrganizer/pageitemdelegate.cpp
@@ -1,242 +1,242 @@
-// 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 .
-
-#include "pageitemdelegate.h"
-#include "pageitemmodel.h"
-#include "pdfwidgetutils.h"
-#include "pdfpainterutils.h"
-#include "pdfrenderer.h"
-#include "pdfcompiler.h"
-#include "pdfconstants.h"
-
-#include
-#include
-
-namespace pdfdocpage
-{
-
-PageItemDelegate::PageItemDelegate(PageItemModel* model, QObject* parent) :
- BaseClass(parent),
- m_model(model),
- m_rasterizer(nullptr)
-{
- m_rasterizer = new pdf::PDFRasterizer(this);
- QSurfaceFormat format;
- format.setSamples(16);
- m_rasterizer->reset(true, format);
-}
-
-PageItemDelegate::~PageItemDelegate()
-{
-
-}
-
-void PageItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
-{
- const PageGroupItem* item = m_model->getItem(index);
-
- if (!item)
- {
- return;
- }
-
- QRect rect = option.rect;
-
- QSize scaledSize = pdf::PDFWidgetUtils::scaleDPI(option.widget, m_pageImageSize);
- int verticalSpacing = pdf::PDFWidgetUtils::scaleDPI_y(option.widget, getVerticalSpacing());
- int horizontalSpacing = pdf::PDFWidgetUtils::scaleDPI_x(option.widget, getHorizontalSpacing());
-
- QRect pageBoundingRect = QRect(QPoint(rect.left() + (rect.width() - scaledSize.width()) / 2, rect.top() + verticalSpacing), scaledSize);
-
- // Draw page preview
- if (!item->groups.empty())
- {
- const PageGroupItem::GroupItem& groupItem = item->groups.front();
- QSizeF rotatedPageSize = pdf::PDFPage::getRotatedBox(QRectF(QPointF(0, 0), groupItem.rotatedPageDimensionsMM), groupItem.pageAdditionalRotation).size();
- QSize pageImageSize = rotatedPageSize.scaled(pageBoundingRect.size(), Qt::KeepAspectRatio).toSize();
- QRect pageImageRect(pageBoundingRect.topLeft() + QPoint((pageBoundingRect.width() - pageImageSize.width()) / 2, (pageBoundingRect.height() - pageImageSize.height()) / 2), pageImageSize);
-
- painter->setBrush(Qt::white);
- painter->drawRect(pageImageRect);
-
- QPixmap pageImagePixmap = getPageImagePixmap(item, pageImageRect);
- if (!pageImagePixmap.isNull())
- {
- painter->drawPixmap(pageImageRect, pageImagePixmap);
- }
-
- painter->setPen(QPen(Qt::black));
- painter->setBrush(Qt::NoBrush);
- painter->drawRect(pageImageRect);
- }
-
- int textOffset = pageBoundingRect.bottom() + verticalSpacing;
- QRect textRect = option.rect;
- textRect.setTop(textOffset);
- textRect.setHeight(option.fontMetrics.lineSpacing());
- painter->drawText(textRect, Qt::AlignCenter | Qt::TextSingleLine, item->groupName);
- textRect.translate(0, textRect.height());
- painter->drawText(textRect, Qt::AlignCenter | Qt::TextSingleLine, item->pagesCaption);
-
- if (option.state.testFlag(QStyle::State_Selected))
- {
- QColor selectedColor = option.palette.color(QPalette::Active, QPalette::Highlight);
- selectedColor.setAlphaF(0.3);
- painter->fillRect(rect, selectedColor);
- }
-
- QPoint tagPoint = rect.topRight() + QPoint(-horizontalSpacing, verticalSpacing);
- for (const QString& tag : item->tags)
- {
- QStringList splitted = tag.split('@', Qt::KeepEmptyParts);
- if (splitted.size() != 2 || splitted.back().isEmpty())
- {
- continue;
- }
-
- QColor color;
- color.setNamedColor(splitted.front());
- QRect bubbleRect = pdf::PDFPainterHelper::drawBubble(painter, tagPoint, color, splitted.back(), Qt::AlignLeft | Qt::AlignBottom);
- tagPoint.ry() += bubbleRect.height() + verticalSpacing;
- }
-}
-
-QSize PageItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
-{
- Q_UNUSED(index);
-
- QSize scaledSize = pdf::PDFWidgetUtils::scaleDPI(option.widget, m_pageImageSize);
- int height = scaledSize.height() + option.fontMetrics.lineSpacing() * 2 + 2 * pdf::PDFWidgetUtils::scaleDPI_y(option.widget, getVerticalSpacing());
- int width = qMax(pdf::PDFWidgetUtils::scaleDPI_x(option.widget, 40), scaledSize.width() + 2 * pdf::PDFWidgetUtils::scaleDPI_x(option.widget, getHorizontalSpacing()));
- return QSize(width, height);
-}
-
-QSize PageItemDelegate::getPageImageSize() const
-{
- return m_pageImageSize;
-}
-
-void PageItemDelegate::setPageImageSize(QSize pageImageSize)
-{
- if (m_pageImageSize != pageImageSize)
- {
- m_pageImageSize = pageImageSize;
- emit sizeHintChanged(QModelIndex());
- }
-}
-
-QPixmap PageItemDelegate::getPageImagePixmap(const PageGroupItem* item, QRect rect) const
-{
- QPixmap pixmap;
-
- Q_ASSERT(item);
- if (item->groups.empty())
- {
- return pixmap;
- }
-
- const PageGroupItem::GroupItem& groupItem = item->groups.front();
- if (groupItem.pageType == PT_Empty)
- {
- return pixmap;
- }
-
- // Jakub Melka: generate key and see, if pixmap is not cached
- QString key = QString("%1#%2#%3#%4#%5@%6x%7").arg(groupItem.documentIndex).arg(groupItem.imageIndex).arg(int(groupItem.pageAdditionalRotation)).arg(groupItem.pageIndex).arg(groupItem.pageType).arg(rect.width()).arg(rect.height());
-
- if (!QPixmapCache::find(key, &pixmap))
- {
- // We must draw the pixmap
- pixmap = QPixmap(rect.width(), rect.height());
- pixmap.fill(Qt::transparent);
-
- switch (groupItem.pageType)
- {
- case pdfdocpage::PT_DocumentPage:
- {
- const auto& documents = m_model->getDocuments();
- auto it = documents.find(groupItem.documentIndex);
- if (it != documents.cend())
- {
- const pdf::PDFDocument& document = it->second.document;
- const pdf::PDFInteger pageIndex = groupItem.pageIndex - 1;
- if (pageIndex >= 0 && pageIndex < pdf::PDFInteger(document.getCatalog()->getPageCount()))
- {
- const pdf::PDFPage* page = document.getCatalog()->getPage(pageIndex);
- Q_ASSERT(page);
-
- pdf::PDFPrecompiledPage compiledPage;
- pdf::PDFFontCache fontCache(pdf::DEFAULT_FONT_CACHE_LIMIT, pdf::DEFAULT_REALIZED_FONT_CACHE_LIMIT);
- pdf::PDFCMSManager cmsManager(nullptr);
- pdf::PDFOptionalContentActivity optionalContentActivity(&document, pdf::OCUsage::View, nullptr);
-
- fontCache.setDocument(pdf::PDFModifiedDocument(const_cast(&document), &optionalContentActivity));
- cmsManager.setDocument(&document);
-
- pdf::PDFCMSPointer cms = cmsManager.getCurrentCMS();
- pdf::PDFRenderer renderer(&document, &fontCache, cms.data(), &optionalContentActivity, pdf::PDFRenderer::getDefaultFeatures(), pdf::PDFMeshQualitySettings());
- renderer.compile(&compiledPage, pageIndex);
-
- QSize imageSize = rect.size();
- QImage pageImage = m_rasterizer->render(pageIndex, page, &compiledPage, imageSize, pdf::PDFRenderer::getDefaultFeatures(), nullptr, groupItem.pageAdditionalRotation);
- pixmap = QPixmap::fromImage(qMove(pageImage));
- }
- }
- break;
- }
-
- case pdfdocpage::PT_Image:
- {
- const auto& images = m_model->getImages();
- auto it = images.find(groupItem.imageIndex);
- if (it != images.cend())
- {
- const QImage& image = it->second.image;
- if (!image.isNull())
- {
- QRect drawRect(QPoint(0, 0), rect.size());
- QRect mediaBox(QPoint(0, 0), image.size());
- QRectF rotatedMediaBox = pdf::PDFPage::getRotatedBox(mediaBox, groupItem.pageAdditionalRotation);
- QMatrix matrix = pdf::PDFRenderer::createMediaBoxToDevicePointMatrix(rotatedMediaBox, drawRect, groupItem.pageAdditionalRotation);
-
- QPainter painter(&pixmap);
- painter.setWorldMatrixEnabled(true);
- painter.setWorldMatrix(matrix);
- painter.translate(0, image.height());
- painter.scale(1.0, -1.0);
- painter.drawImage(0, 0, image);
- }
- }
- break;
- }
-
- case pdfdocpage::PT_Empty:
- Q_ASSERT(false);
- break;
-
- default:
- Q_ASSERT(false);
- break;
- }
-
- QPixmapCache::insert(key, pixmap);
- }
-
- return pixmap;
-}
-
-} // namespace pdfdocpage
+// 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 .
+
+#include "pageitemdelegate.h"
+#include "pageitemmodel.h"
+#include "pdfwidgetutils.h"
+#include "pdfpainterutils.h"
+#include "pdfrenderer.h"
+#include "pdfcompiler.h"
+#include "pdfconstants.h"
+
+#include
+#include
+
+namespace pdfdocpage
+{
+
+PageItemDelegate::PageItemDelegate(PageItemModel* model, QObject* parent) :
+ BaseClass(parent),
+ m_model(model),
+ m_rasterizer(nullptr)
+{
+ m_rasterizer = new pdf::PDFRasterizer(this);
+ QSurfaceFormat format;
+ format.setSamples(16);
+ m_rasterizer->reset(true, format);
+}
+
+PageItemDelegate::~PageItemDelegate()
+{
+
+}
+
+void PageItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
+{
+ const PageGroupItem* item = m_model->getItem(index);
+
+ if (!item)
+ {
+ return;
+ }
+
+ QRect rect = option.rect;
+
+ QSize scaledSize = pdf::PDFWidgetUtils::scaleDPI(option.widget, m_pageImageSize);
+ int verticalSpacing = pdf::PDFWidgetUtils::scaleDPI_y(option.widget, getVerticalSpacing());
+ int horizontalSpacing = pdf::PDFWidgetUtils::scaleDPI_x(option.widget, getHorizontalSpacing());
+
+ QRect pageBoundingRect = QRect(QPoint(rect.left() + (rect.width() - scaledSize.width()) / 2, rect.top() + verticalSpacing), scaledSize);
+
+ // Draw page preview
+ if (!item->groups.empty())
+ {
+ const PageGroupItem::GroupItem& groupItem = item->groups.front();
+ QSizeF rotatedPageSize = pdf::PDFPage::getRotatedBox(QRectF(QPointF(0, 0), groupItem.rotatedPageDimensionsMM), groupItem.pageAdditionalRotation).size();
+ QSize pageImageSize = rotatedPageSize.scaled(pageBoundingRect.size(), Qt::KeepAspectRatio).toSize();
+ QRect pageImageRect(pageBoundingRect.topLeft() + QPoint((pageBoundingRect.width() - pageImageSize.width()) / 2, (pageBoundingRect.height() - pageImageSize.height()) / 2), pageImageSize);
+
+ painter->setBrush(Qt::white);
+ painter->drawRect(pageImageRect);
+
+ QPixmap pageImagePixmap = getPageImagePixmap(item, pageImageRect);
+ if (!pageImagePixmap.isNull())
+ {
+ painter->drawPixmap(pageImageRect, pageImagePixmap);
+ }
+
+ painter->setPen(QPen(Qt::black));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRect(pageImageRect);
+ }
+
+ int textOffset = pageBoundingRect.bottom() + verticalSpacing;
+ QRect textRect = option.rect;
+ textRect.setTop(textOffset);
+ textRect.setHeight(option.fontMetrics.lineSpacing());
+ painter->drawText(textRect, Qt::AlignCenter | Qt::TextSingleLine, item->groupName);
+ textRect.translate(0, textRect.height());
+ painter->drawText(textRect, Qt::AlignCenter | Qt::TextSingleLine, item->pagesCaption);
+
+ if (option.state.testFlag(QStyle::State_Selected))
+ {
+ QColor selectedColor = option.palette.color(QPalette::Active, QPalette::Highlight);
+ selectedColor.setAlphaF(0.3);
+ painter->fillRect(rect, selectedColor);
+ }
+
+ QPoint tagPoint = rect.topRight() + QPoint(-horizontalSpacing, verticalSpacing);
+ for (const QString& tag : item->tags)
+ {
+ QStringList splitted = tag.split('@', Qt::KeepEmptyParts);
+ if (splitted.size() != 2 || splitted.back().isEmpty())
+ {
+ continue;
+ }
+
+ QColor color;
+ color.setNamedColor(splitted.front());
+ QRect bubbleRect = pdf::PDFPainterHelper::drawBubble(painter, tagPoint, color, splitted.back(), Qt::AlignLeft | Qt::AlignBottom);
+ tagPoint.ry() += bubbleRect.height() + verticalSpacing;
+ }
+}
+
+QSize PageItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
+{
+ Q_UNUSED(index);
+
+ QSize scaledSize = pdf::PDFWidgetUtils::scaleDPI(option.widget, m_pageImageSize);
+ int height = scaledSize.height() + option.fontMetrics.lineSpacing() * 2 + 2 * pdf::PDFWidgetUtils::scaleDPI_y(option.widget, getVerticalSpacing());
+ int width = qMax(pdf::PDFWidgetUtils::scaleDPI_x(option.widget, 40), scaledSize.width() + 2 * pdf::PDFWidgetUtils::scaleDPI_x(option.widget, getHorizontalSpacing()));
+ return QSize(width, height);
+}
+
+QSize PageItemDelegate::getPageImageSize() const
+{
+ return m_pageImageSize;
+}
+
+void PageItemDelegate::setPageImageSize(QSize pageImageSize)
+{
+ if (m_pageImageSize != pageImageSize)
+ {
+ m_pageImageSize = pageImageSize;
+ emit sizeHintChanged(QModelIndex());
+ }
+}
+
+QPixmap PageItemDelegate::getPageImagePixmap(const PageGroupItem* item, QRect rect) const
+{
+ QPixmap pixmap;
+
+ Q_ASSERT(item);
+ if (item->groups.empty())
+ {
+ return pixmap;
+ }
+
+ const PageGroupItem::GroupItem& groupItem = item->groups.front();
+ if (groupItem.pageType == PT_Empty)
+ {
+ return pixmap;
+ }
+
+ // Jakub Melka: generate key and see, if pixmap is not cached
+ QString key = QString("%1#%2#%3#%4#%5@%6x%7").arg(groupItem.documentIndex).arg(groupItem.imageIndex).arg(int(groupItem.pageAdditionalRotation)).arg(groupItem.pageIndex).arg(groupItem.pageType).arg(rect.width()).arg(rect.height());
+
+ if (!QPixmapCache::find(key, &pixmap))
+ {
+ // We must draw the pixmap
+ pixmap = QPixmap(rect.width(), rect.height());
+ pixmap.fill(Qt::transparent);
+
+ switch (groupItem.pageType)
+ {
+ case pdfdocpage::PT_DocumentPage:
+ {
+ const auto& documents = m_model->getDocuments();
+ auto it = documents.find(groupItem.documentIndex);
+ if (it != documents.cend())
+ {
+ const pdf::PDFDocument& document = it->second.document;
+ const pdf::PDFInteger pageIndex = groupItem.pageIndex - 1;
+ if (pageIndex >= 0 && pageIndex < pdf::PDFInteger(document.getCatalog()->getPageCount()))
+ {
+ const pdf::PDFPage* page = document.getCatalog()->getPage(pageIndex);
+ Q_ASSERT(page);
+
+ pdf::PDFPrecompiledPage compiledPage;
+ pdf::PDFFontCache fontCache(pdf::DEFAULT_FONT_CACHE_LIMIT, pdf::DEFAULT_REALIZED_FONT_CACHE_LIMIT);
+ pdf::PDFCMSManager cmsManager(nullptr);
+ pdf::PDFOptionalContentActivity optionalContentActivity(&document, pdf::OCUsage::View, nullptr);
+
+ fontCache.setDocument(pdf::PDFModifiedDocument(const_cast(&document), &optionalContentActivity));
+ cmsManager.setDocument(&document);
+
+ pdf::PDFCMSPointer cms = cmsManager.getCurrentCMS();
+ pdf::PDFRenderer renderer(&document, &fontCache, cms.data(), &optionalContentActivity, pdf::PDFRenderer::getDefaultFeatures(), pdf::PDFMeshQualitySettings());
+ renderer.compile(&compiledPage, pageIndex);
+
+ QSize imageSize = rect.size();
+ QImage pageImage = m_rasterizer->render(pageIndex, page, &compiledPage, imageSize, pdf::PDFRenderer::getDefaultFeatures(), nullptr, groupItem.pageAdditionalRotation);
+ pixmap = QPixmap::fromImage(qMove(pageImage));
+ }
+ }
+ break;
+ }
+
+ case pdfdocpage::PT_Image:
+ {
+ const auto& images = m_model->getImages();
+ auto it = images.find(groupItem.imageIndex);
+ if (it != images.cend())
+ {
+ const QImage& image = it->second.image;
+ if (!image.isNull())
+ {
+ QRect drawRect(QPoint(0, 0), rect.size());
+ QRect mediaBox(QPoint(0, 0), image.size());
+ QRectF rotatedMediaBox = pdf::PDFPage::getRotatedBox(mediaBox, groupItem.pageAdditionalRotation);
+ QMatrix matrix = pdf::PDFRenderer::createMediaBoxToDevicePointMatrix(rotatedMediaBox, drawRect, groupItem.pageAdditionalRotation);
+
+ QPainter painter(&pixmap);
+ painter.setWorldMatrixEnabled(true);
+ painter.setWorldMatrix(matrix);
+ painter.translate(0, image.height());
+ painter.scale(1.0, -1.0);
+ painter.drawImage(0, 0, image);
+ }
+ }
+ break;
+ }
+
+ case pdfdocpage::PT_Empty:
+ Q_ASSERT(false);
+ break;
+
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ QPixmapCache::insert(key, pixmap);
+ }
+
+ return pixmap;
+}
+
+} // namespace pdfdocpage
diff --git a/Pdf4QtDocPageOrganizer/pageitemdelegate.h b/Pdf4QtDocPageOrganizer/pageitemdelegate.h
index 65775b6..24d12bc 100644
--- a/Pdf4QtDocPageOrganizer/pageitemdelegate.h
+++ b/Pdf4QtDocPageOrganizer/pageitemdelegate.h
@@ -1,62 +1,62 @@
-// 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 .
-
-#ifndef PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H
-#define PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H
-
-#include "pdfrenderer.h"
-#include "pdfcms.h"
-
-#include
-
-namespace pdfdocpage
-{
-
-class PageItemModel;
-struct PageGroupItem;
-
-class PageItemDelegate : public QAbstractItemDelegate
-{
- Q_OBJECT
-
-private:
- using BaseClass = QAbstractItemDelegate;
-
-public:
- explicit PageItemDelegate(PageItemModel* model, QObject* parent);
- virtual ~PageItemDelegate() override;
-
- virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
- virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
-
- QSize getPageImageSize() const;
- void setPageImageSize(QSize pageImageSize);
-
-private:
- static constexpr int getVerticalSpacing() { return 5; }
- static constexpr int getHorizontalSpacing() { return 5; }
-
- QPixmap getPageImagePixmap(const PageGroupItem* item, QRect rect) const;
-
- PageItemModel* m_model;
- QSize m_pageImageSize;
- pdf::PDFRasterizer* m_rasterizer;
-};
-
-} // namespace pdfdocpage
-
-#endif // PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H
+// 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 .
+
+#ifndef PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H
+#define PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H
+
+#include "pdfrenderer.h"
+#include "pdfcms.h"
+
+#include
+
+namespace pdfdocpage
+{
+
+class PageItemModel;
+struct PageGroupItem;
+
+class PageItemDelegate : public QAbstractItemDelegate
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = QAbstractItemDelegate;
+
+public:
+ explicit PageItemDelegate(PageItemModel* model, QObject* parent);
+ virtual ~PageItemDelegate() override;
+
+ virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+ virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+
+ QSize getPageImageSize() const;
+ void setPageImageSize(QSize pageImageSize);
+
+private:
+ static constexpr int getVerticalSpacing() { return 5; }
+ static constexpr int getHorizontalSpacing() { return 5; }
+
+ QPixmap getPageImagePixmap(const PageGroupItem* item, QRect rect) const;
+
+ PageItemModel* m_model;
+ QSize m_pageImageSize;
+ pdf::PDFRasterizer* m_rasterizer;
+};
+
+} // namespace pdfdocpage
+
+#endif // PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H
diff --git a/Pdf4QtDocPageOrganizer/pageitemmodel.cpp b/Pdf4QtDocPageOrganizer/pageitemmodel.cpp
index ac29929..c666e63 100644
--- a/Pdf4QtDocPageOrganizer/pageitemmodel.cpp
+++ b/Pdf4QtDocPageOrganizer/pageitemmodel.cpp
@@ -1,1282 +1,1282 @@
-// 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