# HG changeset patch # User Matti Hamalainen # Date 1499248135 -10800 # Node ID a5c8741b8662086d85da1b5bd5d57b128e0f6f58 # Parent 907f2ddf6801f703edfb29b6add6d45c13871ac7 Initial prototype support for printing list of users + print preview dialog. Has some issues currently. diff -r 907f2ddf6801 -r a5c8741b8662 Makefile --- a/Makefile Wed Jul 05 09:52:10 2017 +0300 +++ b/Makefile Wed Jul 05 12:48:55 2017 +0300 @@ -4,7 +4,7 @@ ### # Miscellaneous -QT5_MODULES = Core Gui Widgets Sql +QT5_MODULES = Core Gui Widgets Sql PrintSupport QT5_PREFIX = BINTOOL_PREFIX = diff -r 907f2ddf6801 -r a5c8741b8662 Makefile.cross-mingw-win32 --- a/Makefile.cross-mingw-win32 Wed Jul 05 09:52:10 2017 +0300 +++ b/Makefile.cross-mingw-win32 Wed Jul 05 12:48:55 2017 +0300 @@ -3,7 +3,7 @@ ### # Miscellaneous -QT5_MODULES = Core Gui Widgets Sql +QT5_MODULES = Core Gui Widgets Sql PrintSupport QT5_PREFIX ?= /misc/packages/qt5-src QT5_BASE ?= $(QT5_PREFIX)/qtbase BINTOOL_PREFIX ?= i686-w64-mingw32- diff -r 907f2ddf6801 -r a5c8741b8662 build-win32.sh --- a/build-win32.sh Wed Jul 05 09:52:10 2017 +0300 +++ b/build-win32.sh Wed Jul 05 12:48:55 2017 +0300 @@ -33,8 +33,9 @@ do_cpinstall "$QT5_BASE/plugins/" "$TARGET" "platforms" "qwindows.dll" do_cpinstall "$QT5_BASE/plugins/" "$TARGET" "sqldrivers" "qsqlite.dll" + do_cpinstall "$QT5_BASE/plugins/" "$TARGET" "printsupport" "windowsprintersupport.dll" - for i in Core Gui Sql Widgets; do + for i in Core Gui Sql Widgets PrintSupport; do cp -f "$QT5_BASE/lib/Qt5$i.dll" "$TARGET" done diff -r 907f2ddf6801 -r a5c8741b8662 src/main.cpp --- a/src/main.cpp Wed Jul 05 09:52:10 2017 +0300 +++ b/src/main.cpp Wed Jul 05 12:48:55 2017 +0300 @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include "main.h" #include "ui_mainwindow.h" #include "ui_editperson.h" @@ -337,6 +340,8 @@ new QShortcut(QKeySequence(Qt::Key_PageDown), this, SLOT(selectRowNext())); new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this, SLOT(focusDebtEdit())); + + new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_P), this, SLOT(on_button_Print_clicked())); } @@ -506,6 +511,228 @@ } +void SyntilistaMainWindow::on_button_Print_clicked() +{ + // Create a printer object and force some basic settings + QPrinter printer(QPrinter::HighResolution); + printer.setPageSize(QPageSize(QPageSize::A4)); + printer.setColorMode(QPrinter::GrayScale); + printer.setResolution(300); + + // We need to get the page count here, and also need it again in + // printDocument(), but there is no sane way to pass that there, + // so some code duplication is unfortunately necessary + SLPageInfo pinfo; + pinfo.npages = 0; + pinfo.nlinesPerPage = 0; + + QPixmap tmpPixmap(1000, 1300); + QPainter tmpPainter; + tmpPainter.begin(&tmpPixmap); + bool ret = printDocumentPage(pinfo, true, -1, &tmpPainter, &printer); + tmpPainter.end(); + + if (!ret) + { + // Some kind of error occured + return; + } + + + // Set available pages + printer.setFromTo(1, pinfo.npages); + + // Create print preview dialog and show it + QPrintPreviewDialog preview(&printer, this); + preview.setSizeGripEnabled(true); + + connect( + &preview, + SIGNAL(paintRequested(QPrinter *)), + this, + SLOT(printDocument(QPrinter *))); + + preview.exec(); +} + + +void SyntilistaMainWindow::printDocument(QPrinter *printer) +{ + // Create progress dialog + QProgressDialog progress( + tr("Tulostetaan ..."), + tr("Peruuta"), + 0, + 1, + this); + + // Again, get the page info here .. we need the number of lines per page + SLPageInfo pinfo; + pinfo.npages = 0; + pinfo.nlinesPerPage = 0; + + QPixmap tmpPixmap(1000, 1300); + QPainter tmpPainter; + tmpPainter.begin(&tmpPixmap); + bool ret = printDocumentPage(pinfo, true, -1, &tmpPainter, printer); + tmpPainter.end(); + + if (!ret) + return; + + // Setup rest of the progress dialog here + progress.setWindowModality(Qt::ApplicationModal); + progress.setMinimum(printer->fromPage() - 1); + progress.setMaximum(printer->toPage()); + + + // Begin painting to the printer (or preview) + QPainter painter; + painter.begin(printer); + + bool firstPage = true; + for (int page = printer->fromPage(); page <= printer->toPage(); page++) + { + if (!firstPage) + printer->newPage(); + + qApp->processEvents(); + if (progress.wasCanceled()) + break; + + printDocumentPage(pinfo, false, page, &painter, printer); + progress.setValue(page); + firstPage = false; + } + + painter.end(); +} + + +bool SyntilistaMainWindow::printDocumentPage(SLPageInfo &pinfo, const bool getPageInfo, const int npage, QPainter *pt, QPrinter *printer) +{ + // Form the SQL query for list of users + QString querystr = QStringLiteral( + "SELECT id,first_name,last_name,extra_info,added,updated, " + "(SELECT TOTAL(value) FROM transactions WHERE transactions.person=people.id) AS balance " + "FROM people ORDER BY last_name ASC,first_name ASC"); + + // If we are fetching page info, we need to process all entries + if (!getPageInfo) + { + // Otherwise we can limit to given page number + querystr += QStringLiteral(" LIMIT %1 OFFSET %2"). + arg(pinfo.nlinesPerPage). + arg((npage - 1) * pinfo.nlinesPerPage); + } + + QSqlQuery query; + query.prepare(querystr); + query.setForwardOnly(true); + query.exec(); + + if (!slCheckAndReportSQLError("printDocumentPage()", query.lastError())) + { + slErrorMsg( + tr("SQL-tietokantavirhe"), + tr("Tietokantaa selattaessa tapahtui virhe.")); + + return false; + } + + pt->save(); + if (!getPageInfo) + { + pt->scale( + printer->pageRect().width() / 1000.0f, + printer->pageRect().height() / 1300.0f); + } + + QFont font1("Arial", 5); + SLDrawContext ctx(pt); + ctx.setFont(font1); + + int nline = 0; + while (query.next()) + { + PersonInfo info; + slGetPersonInfoRec(query, info); + + // Check for end of page + // KLUDGE for now + if (getPageInfo && + ctx.m_pos.y() + (ctx.boundRect().height() * 4) >= 1300.0f / 2.0f) + { + if (nline > pinfo.nlinesPerPage) + pinfo.nlinesPerPage = nline; + + pinfo.npages++; + nline = 0; + } + + if (nline == 0) + { + // If we are at the start of the page, we shall draw a header + pt->setBrush(QBrush(Qt::black)); + pt->setPen(QPen(Qt::black, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + + ctx.setPos(0, 0); + ctx.drawText( 5, 180, "Etunimi"); + ctx.drawText( 200, 230, "Sukunimi"); + ctx.drawText( 450, 190, "Lisätty"); + ctx.drawText( 650, 190, "Päivitetty"); + ctx.drawText( 870, 120, "Tase"); + ctx.lf(); + + pt->drawLine(0, ctx.m_pos.y(), 1000, ctx.m_pos.y()); + + ctx.move(0, 5); + } + + // Draw a gray bar under every second line + if (nline % 2 == 0) + { + pt->fillRect( + 0, + ctx.m_pos.y() - 1, + 1000, + ctx.boundRect().height() + 4, + QColor(0, 0, 0, 40)); + } + + ctx.drawText( 5, 180, info.firstName); + ctx.drawText( 200, 230, info.lastName); + ctx.drawText( 450, 190, slDateTimeToStr(info.added)); + ctx.drawText( 650, 190, slDateTimeToStr(info.updated)); + ctx.drawText( 870, 120, slMoneyValueToStr(info.balance), Qt::AlignRight); + + ctx.lf(10); + nline++; + } + + query.finish(); + + if (getPageInfo) + { + if (nline > pinfo.nlinesPerPage) + pinfo.nlinesPerPage = nline; + + pinfo.npages++; + } + else + { + ctx.setPos(0, 1240); + ctx.drawText(0, 1000, + QStringLiteral("Sivu %1 / %2"). + arg(npage).arg(printer->toPage()), + Qt::AlignHCenter); + } + + pt->restore(); + return true; +} + + void SyntilistaMainWindow::on_button_DeletePerson_clicked() { if (currPerson.id <= 0) diff -r 907f2ddf6801 -r a5c8741b8662 src/main.h --- a/src/main.h Wed Jul 05 09:52:10 2017 +0300 +++ b/src/main.h Wed Jul 05 12:48:55 2017 +0300 @@ -14,6 +14,8 @@ #include #include #include +#include +#include // @@ -106,6 +108,13 @@ class AboutWindow; } +typedef struct +{ + int nlinesPerPage; + int npages; +} SLPageInfo; + + class SyntilistaMainWindow : public QMainWindow { Q_OBJECT @@ -123,6 +132,8 @@ int addTransactionGUI(qint64 id, bool debt, double value); void updatePersonList(); + bool printDocumentPage(SLPageInfo &pinfo, const bool getPageInfo, const int page, QPainter *pt, QPrinter *printer); + PersonSQLModel *model_People; public slots: @@ -138,6 +149,7 @@ void on_button_Quit_clicked(); void on_button_About_clicked(); + void on_button_Print_clicked(); void on_button_AddDebt_clicked(); void on_button_PayDebt_clicked(); @@ -156,6 +168,8 @@ void updateSortOrder(int index, Qt::SortOrder order); + void printDocument(QPrinter *printer); + private: Ui::SyntilistaMainWindow *ui; @@ -222,4 +236,114 @@ }; +// +// Custom painter drawing helper class +// +class SLDrawContext : public QObject +{ + Q_OBJECT + +public: + QPointF m_pos; + QString m_str; + qreal m_lf_add; + + explicit SLDrawContext(QPainter *pt) + { + painter = pt; + metrics = NULL; + m_str = "ABC"; + setPos(0, 0); + m_lf_add = 0; + } + + ~SLDrawContext() + { + if (metrics) + delete metrics; + } + + void setFont(const QFont &ft) + { + if (metrics) + delete metrics; + + font = QFont(ft, painter->device()); + painter->setFont(font); + metrics = new QFontMetricsF(font); + } + + void setLFAdd(const qreal lf_add) + { + m_lf_add = lf_add; + } + + void drawText(const QPointF &pos, const QString &str) + { + m_str = str; + painter->drawText(m_pos + pos, str); + } + + void drawText(const QString &str) + { + drawText(QPointF(0, 0), str); + } + + void drawText(const qreal xc, const qreal width, const QString &str, const int flags = 0) + { + m_str = str; + painter->drawText( + m_pos.x() + xc, m_pos.y(), + width, boundRect().height(), + flags, + str); + } + + const QRectF boundRect(const QString str) + { + return metrics->boundingRect(str); + } + + const QRectF boundRect() + { + return metrics->boundingRect(m_str); + } + + void lf(qreal yadd) + { + m_pos.setY(m_pos.y() + boundRect().height() + yadd); + } + + void lf() + { + lf(m_lf_add); + } + + void setPos(const QPointF &pos) + { + m_pos = pos; + } + + void setPos(const qreal x, const qreal y) + { + setPos(QPointF(x, y)); + } + + void move(const QPointF &pos) + { + m_pos += pos; + } + + void move(const qreal x, const qreal y) + { + move(QPointF(x, y)); + } + +private: + QPainter *painter; + QFont font; + QFontMetricsF *metrics; +}; + + #endif // SYNTILISTA_H diff -r 907f2ddf6801 -r a5c8741b8662 src/mainwindow.ui --- a/src/mainwindow.ui Wed Jul 05 09:52:10 2017 +0300 +++ b/src/mainwindow.ui Wed Jul 05 12:48:55 2017 +0300 @@ -262,6 +262,13 @@ + + + Tulosta + + + + Qt::Horizontal