1 #ifndef PDFEXPORT_H
2 #define PDFEXPORT_H
3 
4 #include "pdfexport_global.h"
5 #include "plugins/genericexportplugin.h"
6 #include "config_builder.h"
7 #include <QPdfWriter>
8 #include <QFont>
9 #include <QColor>
10 
11 class QPagedPaintDevice;
12 class QPainter;
13 class QTextOption;
14 class QFont;
15 
16 namespace Cfg
17 {
18     PDFEXPORTSHARED_EXPORT QFont getPdfExportDefaultFont();
19     PDFEXPORTSHARED_EXPORT QStringList getPdfPageSizes();
20 }
21 
22 CFG_CATEGORIES(PdfExportConfig,
23     CFG_CATEGORY(PdfExport,
24         CFG_ENTRY(QString,     PageSize,         "A4")
25         CFG_ENTRY(QStringList, PageSizes,        Cfg::getPdfPageSizes())
26         CFG_ENTRY(int,         Padding,          1)
27         CFG_ENTRY(bool,        PrintRowNum,      true)
28         CFG_ENTRY(bool,        PrintPageNumbers, true)
29         CFG_ENTRY(int,         TopMargin,        20)
30         CFG_ENTRY(int,         RightMargin,      20)
31         CFG_ENTRY(int,         BottomMargin,     20)
32         CFG_ENTRY(int,         LeftMargin,       20)
33         CFG_ENTRY(int,         MaxCellBytes,     100)
34         CFG_ENTRY(QFont,       Font,             Cfg::getPdfExportDefaultFont())
35         CFG_ENTRY(int,         FontSize,         10)
36         CFG_ENTRY(QColor,      HeaderBgColor,    QColor(Qt::lightGray))
37         CFG_ENTRY(QColor,      NullValueColor,   QColor(Qt::gray))
38     )
39 )
40 
41 class PDFEXPORTSHARED_EXPORT PdfExport : public GenericExportPlugin
42 {
43         Q_OBJECT
44         SQLITESTUDIO_PLUGIN("pdfexport.json")
45 
46     public:
47         QString getFormatName() const;
48         ExportManager::StandardConfigFlags standardOptionsToEnable() const;
49         ExportManager::ExportProviderFlags getProviderFlags() const;
50         void validateOptions();
51         CfgMain* getConfig();
52         QString getExportConfigFormName() const;
53         QString defaultFileExtension() const;
54         bool beforeExportQueryResults(const QString& query, QList<QueryExecutor::ResultColumnPtr>& columns,
55                                       const QHash<ExportManager::ExportProviderFlag,QVariant> providedData);
56         bool exportQueryResultsRow(SqlResultsRowPtr row);
57         bool exportTable(const QString& database, const QString& table, const QStringList& columnNames, const QString& ddl, SqliteCreateTablePtr createTable,
58                          const QHash<ExportManager::ExportProviderFlag,QVariant> providedData);
59         bool exportVirtualTable(const QString& database, const QString& table, const QStringList& columnNames, const QString& ddl, SqliteCreateVirtualTablePtr createTable,
60                                 const QHash<ExportManager::ExportProviderFlag,QVariant> providedData);
61         bool afterExport();
62         bool afterExportTable();
63         bool afterExportQueryResults();
64         bool exportTableRow(SqlResultsRowPtr data);
65         bool beforeExportDatabase(const QString& database);
66         bool exportIndex(const QString& database, const QString& name, const QString& ddl, SqliteCreateIndexPtr createIndex);
67         bool exportTrigger(const QString& database, const QString& name, const QString& ddl, SqliteCreateTriggerPtr createTrigger);
68         bool exportView(const QString& database, const QString& name, const QString& ddl, SqliteCreateViewPtr view);
69         void cleanupAfterExport();
70         bool isBinaryData() const;
71         bool init();
72         void deinit();
73 
74     protected:
75         virtual QPagedPaintDevice* createPaintDevice(const QString& documentTitle, bool& takeOwnership);
76 
77         int lineWidth = 15;
78 
79     private:
80         struct DataCell
81         {
82             QString contents;
83             Qt::Alignment alignment = Qt::AlignLeft;
84             bool isNull = false;
85             bool isRowNum = false;
86         };
87 
88         struct DataRow
89         {
90             enum class Type
91             {
92                 NORMAL,
93                 TOP_HEADER,
94                 COLUMNS_HEADER
95             };
96 
97             QList<DataCell> cells;
98             int height = 0;
99             Type type = Type::NORMAL;
100         };
101 
102         struct ObjectCell
103         {
104             enum class Type
105             {
106                 NORMAL,
107                 LIST
108             };
109 
110             QStringList contents;
111             Qt::Alignment alignment = Qt::AlignLeft;
112             bool headerBackground = false;
113             bool bold = false;
114             bool italic = false;
115             Type type = Type::NORMAL;
116         };
117 
118         struct ObjectRow
119         {
120             enum class Type
121             {
122                 MULTI,
123                 SINGLE
124             };
125 
126             QList<ObjectCell> cells;
127             int height = 0;
128             Type type = Type::SINGLE;
129             bool recalculateColumnWidths = false;
130         };
131 
132         void prepareTableDataExport(const QString& table, const QStringList& columnNames, const QHash<ExportManager::ExportProviderFlag,QVariant> providedData);
133         QList<int> getColumnDataLengths(int columnCount, const QHash<ExportManager::ExportProviderFlag,QVariant> providedData);
134         bool beginDoc(const QString& title);
135         void endDoc();
136         void setupConfig();
137         void updateMargins();
138         void drawDdl(const QString& objName, const QString& ddl);
139         void clearDataHeaders();
140         void resetDataTable();
141         void exportDataHeader(const QString& contents);
142         void exportDataColumnsHeader(const QStringList& columns);
143         void exportDataRow(const QList<QVariant>& data);
144         void exportObjectHeader(const QString& contents);
145         void exportObjectColumnsHeader(const QStringList& columns);
146         void exportTableColumnRow(SqliteCreateTable::Column* column);
147         void exportTableConstraintsRow(const QList<SqliteCreateTable::Constraint*>& constrList);
148         void exportObjectRow(const QStringList& values);
149         void exportObjectRow(const QString& values);
150         void checkForDataRender();
151         void flushObjectPages();
152         void drawObjectTopLine(int y);
153         void drawObjectCellHeaderBackground(int x1, int y1, int x2, int y2);
154         void drawFooter();
155         void flushObjectRow(const ObjectRow& row, int y);
156         void flushObjectCell(const ObjectCell& cell, int x, int y, int w, int h);
157         void flushDataPages(bool forceRender = false);
158         void flushDataRowsPage(int columnStart, int columnEndBefore, int rowsToRender);
159         void flushDataRow(const DataRow& row, int& y, int columnStart, int columnEndBefore, int localRowNum);
160         void flushDataCell(const QRect& rect, const DataCell& cell);
161         void flushDataCell(const QRect& rect, const QString& contents, QTextOption* opt);
162         void flushDataHeaderRow(const DataRow& row, int& y, int totalColsWidth, int columnStart, int columnEndBefore);
163         void flushDataHeaderCell(int& x, int y, const DataRow& row, int col, QTextOption* opt);
164         void renderPageNumber();
165         int getPageNumberHeight();
166         void newPage();
167         void calculateDataColumnWidths(const QStringList& columnNames, const QList<int>& columnDataLengths, int columnToExpand = -1);
168         void calculateDataRowHeights();
169         int calculateRowHeight(int textWidth, const QString& contents);
170         int calculateRowHeight(int maxTextWidth, const QStringList& listContents);
171         int calculateBulletPrefixWidth();
172         void calculateObjectColumnWidths(int columnToExpand = -1);
173         int correctMaxObjectColumnWidths(int colCount, int columnToExpand);
174         void calculateObjectRowHeights();
175         int getDataColumnsWidth() const;
176         int getDataColumnsStartX() const;
177         int getContentsLeft() const;
178         int getContentsTop() const;
179         int getContentsRight() const;
180         int getContentsBottom() const;
181         qreal mmToPoints(qreal sizeMM);
182 
183         CFG_LOCAL_PERSISTABLE(PdfExportConfig, cfg)
184         QPagedPaintDevice* pagedWriter = nullptr;
185         bool takeDeviceOwnership = true;
186         QPainter* painter = nullptr;
187         QTextOption* textOption = nullptr;
188         QFont stdFont;
189         QFont boldFont;
190         QFont italicFont;
191         int totalRows = 0;
192         QList<ObjectRow> bufferedObjectRows; // object rows (for exporting ddl of all object)
193         QList<DataRow> bufferedDataRows; // data rows
194         int totalHeaderRowsHeight = 0; // total height of all current header rows
195         int currentHeaderMinWidth = 0; // minimum width of the object header, required to extend data columns when hey are slimmer than this
196         QList<int> calculatedObjectColumnWidths; // object column widths calculated basing on header column widths and columns from other object rows
197         QList<int> calculatedDataColumnWidths; // data column widths calculated basing on header column widths and data column widths
198         QList<int> columnsPerPage; // number of columns that will fit on each page
199         QScopedPointer<DataRow> headerRow; // Top level header (object name)
200         QScopedPointer<DataRow> columnsHeaderRow; // columns header for data tables
201         int rowNumColumnWidth = 0;
202         int pageWidth = 0;
203         int pageHeight = 0;
204         int minRowHeight = 0;
205         int rowsToPrebuffer = 0;
206         int currentPage = -1;
207         int rowNum = 0;
208         int lastRowY = 0;
209         qreal pointsPerMm = 1.0;
210         int maxColWidth = 0;
211         int maxRowHeight = 0;
212         int cellDataLimit = 100;
213 
214         static QString bulletChar;
215 
216         // Configurable fields
217         int padding = 0;
218         bool printRowNum = true;
219         bool printPageNumbers = true;
220         int topMargin = 0;
221         int rightMargin = 0;
222         int leftMargin = 0;
223         int bottomMargin = 0;
224 };
225 
226 #endif // PDFEXPORT_H
227