00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kexisimpleprintingengine.h"
00021
00022 #include <core/keximainwindow.h>
00023 #include <kexiutils/utils.h>
00024
00025 #include <kapplication.h>
00026 #include <kiconloader.h>
00027 #include <klocale.h>
00028 #include <kfontdialog.h>
00029 #include <kurllabel.h>
00030 #include <kdebug.h>
00031
00032 #include <qlabel.h>
00033 #include <qlayout.h>
00034 #include <qpainter.h>
00035 #include <qcheckbox.h>
00036 #include <qwhatsthis.h>
00037 #include <qpaintdevicemetrics.h>
00038 #include <qimage.h>
00039
00040 #include <kexiutils/tristate.h>
00041 #include <kexidb/connection.h>
00042 #include <kexidb/tableschema.h>
00043 #include <kexidb/cursor.h>
00044 #include <kexidb/utils.h>
00045 #include <kexidb/queryschema.h>
00046
00047 KexiSimplePrintingSettings::KexiSimplePrintingSettings()
00048 {
00049 pageLayout = KoPageLayout::standardLayout();
00050 addPageNumbers = true;
00051 addDateAndTime = true;
00052 addTableBorders = false;
00053 pageTitleFont = kapp->font();
00054 pageTitleFont.setPointSizeFloat( (double)QFontInfo(pageTitleFont).pointSize()*1.5 );
00055 pageTitleFont.setBold(true);
00056 }
00057
00058 KexiSimplePrintingSettings::~KexiSimplePrintingSettings()
00059 {
00060 }
00061
00062 KexiSimplePrintingSettings KexiSimplePrintingSettings::load()
00063 {
00064 KexiSimplePrintingSettings settings;
00065
00066 KConfig *config = kapp->config();
00067 config->setGroup("Simple Printing");
00068 if (config->hasKey("pageTitleFont"))
00069 settings.pageTitleFont = config->readFontEntry("pageTitleFont");
00071 if (config->hasKey("pageFormat"))
00072 settings.pageLayout.format = KoPageFormat::formatFromString(
00073 config->readEntry("pageFormat" ) );
00074 if (config->readEntry("pageOrientation", "portrait").lower()=="landscape")
00075 settings.pageLayout.orientation = PG_LANDSCAPE;
00076 else
00077 settings.pageLayout.orientation = PG_PORTRAIT;
00078 if (config->hasKey("pageWidth"))
00079 settings.pageLayout.ptWidth = config->readDoubleNumEntry("pageWidth");
00080 if (config->hasKey("pageHeight"))
00081 settings.pageLayout.ptHeight = config->readDoubleNumEntry("pageHeight");
00082 if (config->hasKey("pageLeftMargin"))
00083 settings.pageLayout.ptLeft = config->readDoubleNumEntry("pageLeftMargin");
00084 if (config->hasKey("pageRightMargin"))
00085 settings.pageLayout.ptRight = config->readDoubleNumEntry("pageRightMargin");
00086 if (config->hasKey("pageTopMargin"))
00087 settings.pageLayout.ptTop = config->readDoubleNumEntry("pageTopMargin");
00088 if (config->hasKey("pageBottomMargin"))
00089 settings.pageLayout.ptBottom = config->readDoubleNumEntry("pageBottomMargin");
00090 settings.addPageNumbers = config->readBoolEntry("addPageNumbersToPage", true);
00091 settings.addDateAndTime = config->readBoolEntry("addDateAndTimePage", true);
00092 settings.addTableBorders = config->readBoolEntry("addTableBorders", false);
00093 return settings;
00094 }
00095
00096 void KexiSimplePrintingSettings::save()
00097 {
00098 KConfig *config = kapp->config();
00099 config->setGroup("Simple Printing");
00100 config->writeEntry( "pageTitleFont", pageTitleFont );
00101 config->writeEntry( "pageFormat", KoPageFormat::formatString( pageLayout.format ) );
00102 config->writeEntry("pageOrientation",
00103 pageLayout.orientation == PG_PORTRAIT ? "portrait" : "landscape");
00104 config->writeEntry("pageWidth", pageLayout.ptWidth);
00105 config->writeEntry("pageHeight", pageLayout.ptHeight);
00106 config->writeEntry("pageLeftMargin", pageLayout.ptLeft);
00107 config->writeEntry("pageRightMargin", pageLayout.ptRight);
00108 config->writeEntry("pageTopMargin", pageLayout.ptTop);
00109 config->writeEntry("pageBottomMargin", pageLayout.ptBottom);
00110 config->writeEntry("addPageNumbersToPage", addPageNumbers);
00111 config->writeEntry("addDateAndTimePage", addDateAndTime);
00112 config->writeEntry("addTableBorders", addTableBorders);
00113 config->sync();
00114 }
00115
00116
00117
00118 KexiSimplePrintingEngine::KexiSimplePrintingEngine(
00119 const KexiSimplePrintingSettings& settings, QObject* parent)
00120 : QObject(parent, "KexiSimplePrintingEngine")
00121 , m_settings(&settings)
00122 , m_pdm(0)
00123 {
00124 m_cursor = 0;
00125 m_data = 0;
00126 m_visibleFieldsCount = 0;
00127 m_dataOffsets.setAutoDelete(true);
00128 clear();
00129 }
00130
00131 KexiSimplePrintingEngine::~KexiSimplePrintingEngine()
00132 {
00133 done();
00134 }
00135
00136 bool KexiSimplePrintingEngine::init(KexiDB::Connection& conn,
00137 KexiDB::TableOrQuerySchema& tableOrQuery, const QString& titleText, QString& errorMessage)
00138 {
00139 errorMessage = QString::null;
00140 done();
00141 m_headerText = titleText;
00142
00143
00144 KexiDB::QuerySchema *query = 0;
00145 if (tableOrQuery.table())
00146 query = tableOrQuery.table()->query();
00147 else
00148 query = tableOrQuery.query();
00149 if (!query) {
00150 errorMessage = i18n("Could not load data from table or query.");
00151 return false;
00152 }
00153
00154 m_cursor = conn.executeQuery(*query);
00155 if (!m_cursor) {
00156 conn.debugError();
00157 return false;
00158 }
00159 bool ok = !m_cursor->error();
00160 if (ok) {
00161 m_data = new KexiTableViewData(m_cursor);
00163 m_data->preloadAllRows();
00164 m_fieldsExpanded = query->fieldsExpanded( KexiDB::QuerySchema::WithInternalFields );
00165 m_visibleFieldsCount = m_cursor->query()->fieldsExpanded().count();
00166 }
00167 else {
00168 conn.debugError();
00169 }
00170 m_eof = !ok || m_data->count() == 0;
00171 conn.deleteCursor(m_cursor);
00172 m_cursor = 0;
00173 return ok;
00174 }
00175
00176 bool KexiSimplePrintingEngine::done()
00177 {
00178 bool result = true;
00179 if (m_cursor && (m_cursor->error() || !m_cursor->connection()->deleteCursor(m_cursor))) {
00180 m_cursor->debugError();
00181 result = false;
00182 }
00183 m_cursor = 0;
00184 delete m_data;
00185 m_data = 0;
00186 m_pagesCount = 0;
00187 m_paintInitialized = false;
00188 m_fieldsExpanded.clear();
00189 m_visibleFieldsCount = 0;
00190 return result;
00191 }
00192
00193 void KexiSimplePrintingEngine::clear()
00194 {
00195 m_eof = false;
00196 m_pagesCount = 0;
00197 m_dataOffsets.clear();
00198 m_dataOffsets.append(new uint(0));
00199 m_paintInitialized = false;
00200 }
00201
00202 void KexiSimplePrintingEngine::paintPage(int pageNumber, QPainter& painter, bool paint)
00203 {
00204 uint offset = 0;
00205 if (pageNumber < (int)m_dataOffsets.count()) {
00206 offset = *m_dataOffsets.at(pageNumber);
00207 }
00208
00209 double y = 0.0;
00210
00211 const bool printing = painter.device()->devType() == QInternal::Printer;
00212 m_SCALE = printing ? 1 : 20;
00213
00214 double w, h;
00215 m_pdm = QPaintDeviceMetrics( painter.device() );
00216
00217 if (dynamic_cast<QWidget*>(painter.device())) {
00218 w = dynamic_cast<QWidget*>(painter.device())->width() * m_SCALE;
00219 h = dynamic_cast<QWidget*>(painter.device())->height() * m_SCALE;
00220 }
00221 else if (dynamic_cast<QPixmap*>(painter.device())) {
00222 w = dynamic_cast<QPixmap*>(painter.device())->width() * m_SCALE;
00223 h = dynamic_cast<QPixmap*>(painter.device())->height() * m_SCALE;
00224 }
00225 else {
00226 w = m_pdm.widthMM();
00227 h = m_pdm.heightMM();
00228 }
00229
00230 if (!m_paintInitialized) {
00231 m_paintInitialized = true;
00232
00233 double widthMM = KoPageFormat::width(
00234 m_settings->pageLayout.format, m_settings->pageLayout.orientation);
00235 double heightMM = KoPageFormat::height(
00236 m_settings->pageLayout.format, m_settings->pageLayout.orientation);
00237
00238 m_dpiY = m_pdm.logicalDpiY();
00239 m_dpiX = m_pdm.logicalDpiX();
00240 #ifdef Q_WS_WIN //fix for 120dpi
00241 if (!printing) {
00242 m_dpiY = 96;
00243 m_dpiX = 96;
00244
00245
00246 }
00247 #endif
00248 double pdWidthMM = m_pdm.widthMM();
00249 double pdHeightMM = m_pdm.heightMM();
00250
00251
00252
00253
00254 m_leftMargin = POINT_TO_INCH(m_settings->pageLayout.ptLeft)*m_dpiX * (double)m_SCALE;
00255 m_rightMargin = POINT_TO_INCH(m_settings->pageLayout.ptRight)*m_dpiX * (double)m_SCALE;
00256 m_topMargin = POINT_TO_INCH(m_settings->pageLayout.ptTop)*m_dpiY * (double)m_SCALE;
00257 m_bottomMargin = POINT_TO_INCH(m_settings->pageLayout.ptBottom)*m_dpiY * (double)m_SCALE;
00258
00259 m_fx = widthMM / (pdWidthMM);
00260 m_fy = heightMM / (pdHeightMM);
00261
00262
00263
00264 m_pageWidth = uint( m_fx*double(m_pdm.width()) * m_SCALE - m_leftMargin - m_rightMargin );
00265 m_pageHeight = uint( m_fy*double(m_pdm.height()) * m_SCALE - m_topMargin - m_bottomMargin );
00266 m_headerFont = m_settings->pageTitleFont;
00267 if(!printing) {
00268 int pixelSize = int( POINT_TO_INCH((double)QFontInfo(m_headerFont).pointSize())*m_dpiX ) * m_SCALE;
00269 m_headerFont.setPixelSize(pixelSize);
00270 }
00271
00273 m_mainFont = kapp->font();
00274 if(!printing) {
00275 int pixelSize = int( POINT_TO_INCH(m_mainFont.pointSizeFloat())*m_dpiX )
00276 * m_SCALE;
00277 m_mainFont.setPixelSize(pixelSize);
00278 }
00279 painter.setFont(m_mainFont);
00280
00281 m_dateTimeText = KGlobal::locale()->formatDateTime(QDateTime::currentDateTime(),
00282 true, false);
00283 m_dateTimeWidth = painter.fontMetrics().width(m_dateTimeText+" ");
00284 m_mainLineSpacing = painter.fontMetrics().lineSpacing();
00285 m_footerHeight = m_mainLineSpacing * 2;
00286 painter.setFont(m_headerFont);
00287 m_headerTextRect = painter.fontMetrics().boundingRect(
00288 (int)m_leftMargin, (int)m_topMargin,
00289 m_pageWidth - m_dateTimeWidth,
00290 m_pageHeight, Qt::AlignAuto|Qt::WordBreak, m_headerText);
00291 m_headerTextRect.setRight(m_headerTextRect.right()+10);
00292 m_headerTextRect.setWidth(
00293 QMIN(int(m_pageWidth - m_dateTimeWidth), m_headerTextRect.width()));
00294
00295
00296 m_maxFieldNameWidth = 0;
00297
00298 painter.setFont(m_mainFont);
00299 for (uint i=0; i < m_visibleFieldsCount; i++) {
00300 const int newW =
00301 painter.fontMetrics().width(m_fieldsExpanded[i]->captionOrAliasOrName()+":");
00302
00303
00304 if (m_maxFieldNameWidth < newW)
00305 m_maxFieldNameWidth = newW;
00306 }
00307 m_maxFieldNameWidth += painter.fontMetrics().width("ww");
00308 }
00309
00310
00311 if(!printing) {
00312 painter.setWindow(0, 0, int(w*m_fx), int(h*m_fy));
00313 }
00314
00315
00316 painter.setFont(m_headerFont);
00317 if (paint) {
00318 painter.drawText(m_headerTextRect, Qt::AlignAuto|Qt::WordBreak, m_headerText);
00319 }
00320 painter.setFont(m_mainFont);
00321 if (paint) {
00322 painter.drawText((int)m_leftMargin + m_pageWidth - m_dateTimeWidth,
00323 (int)m_topMargin, m_dateTimeWidth,
00324 m_headerTextRect.height(), Qt::AlignRight, m_dateTimeText);
00325
00326 QString pageNumString;
00327 if (m_pagesCount>0)
00328 pageNumString = i18n("Page (number) of (total)", "Page %1 of %2")
00329 .arg(pageNumber+1).arg(m_pagesCount);
00330 else
00331 pageNumString = i18n("Page %1").arg(pageNumber+1);
00332 painter.drawText((int)m_leftMargin,
00333 (int)m_topMargin + m_pageHeight - m_mainLineSpacing,
00334 m_pageWidth, m_mainLineSpacing,
00335 Qt::AlignRight | Qt::AlignBottom, pageNumString);
00336 painter.drawLine((int)m_leftMargin,
00337 (int)m_topMargin + m_pageHeight - m_mainLineSpacing*3/2,
00338 (int)m_leftMargin + m_pageWidth,
00339 (int)m_topMargin + m_pageHeight - m_mainLineSpacing*3/2);
00340 }
00341 y = (double)m_topMargin + (double)m_headerTextRect.height() + double(m_mainLineSpacing)/2;
00342 if (!m_settings->addTableBorders) {
00343
00344 if (paint)
00345 painter.drawLine((int)m_leftMargin, (int)y, (int)m_leftMargin + m_pageWidth-1, (int)y);
00346 y += (double)m_mainLineSpacing;
00347 }
00348
00349
00350 KexiDB::RowData row;
00351 KexiTableItem *item;
00352
00353
00354 const uint rows = m_data->count();
00355 const int cellMargin = m_settings->addTableBorders ?
00356 painter.fontMetrics().width("i") : 0;
00357 uint paintedRows = 0;
00358 for (;offset < rows; ++offset) {
00359 item = m_data->at(offset);
00360
00361
00362 double newY = y;
00363 paintRecord(painter, item, cellMargin, newY, paintedRows, false, printing);
00364
00365 if (newY > (m_topMargin + m_pageHeight - m_mainLineSpacing*2 + m_mainLineSpacing) && paintedRows > 0) {
00366
00367
00369 break;
00370 }
00371
00372
00373
00374
00375
00376
00377 if (paint)
00378 paintRecord(painter, item, cellMargin, y, paintedRows, paint, printing);
00379 else
00380 y = newY;
00381 paintedRows++;
00382 }
00383
00384 if (int(m_dataOffsets.count()-1)==pageNumber) {
00385 m_dataOffsets.append(new uint(offset));
00386 }
00387 m_eof = offset == rows;
00388 }
00389
00390 void KexiSimplePrintingEngine::paintRecord(QPainter& painter, KexiTableItem *item,
00391 int cellMargin, double &y, uint paintedRows, bool paint, bool printing)
00392 {
00393 if (paintedRows>0 && !m_settings->addTableBorders) {
00394 if (paint) {
00395 painter.setPen(Qt::darkGray);
00396 painter.drawLine(
00397 int(m_leftMargin), int( y-(double)m_mainLineSpacing ),
00398 int(m_leftMargin)+m_pageWidth-1, int(y-(double)m_mainLineSpacing));
00399 painter.setPen(Qt::black);
00400 }
00401 }
00402
00403 for (uint i=0; i<m_visibleFieldsCount; i++) {
00404
00405 if (paint) {
00406 painter.drawText(
00407 (int)m_leftMargin+cellMargin, (int)y, m_maxFieldNameWidth-cellMargin*2, m_mainLineSpacing,
00408 Qt::AlignTop, m_fieldsExpanded[i]->captionOrAliasOrName()
00409 + (m_settings->addTableBorders ? "" : ":"));
00410 }
00411 QString text;
00413
00414 KexiDB::QueryColumnInfo* ci;
00415 int indexForVisibleLookupValue = m_fieldsExpanded[i]->indexForVisibleLookupValue();
00416 if (-1 != indexForVisibleLookupValue && indexForVisibleLookupValue < (int)item->count())
00417 ci = m_fieldsExpanded[ indexForVisibleLookupValue ];
00418 else {
00419 ci = m_fieldsExpanded[ i ];
00420 indexForVisibleLookupValue = i;
00421 }
00422
00423 QVariant v(item->at( indexForVisibleLookupValue ));
00424 KexiDB::Field::Type ftype = ci->field->type();
00425 QRect rect( (int)m_leftMargin + m_maxFieldNameWidth + cellMargin, (int)y,
00426 m_pageWidth - m_maxFieldNameWidth - cellMargin*2, m_pageHeight - (int)y);
00427
00428 if (v.isNull() || !v.isValid()) {
00429
00430 }
00432 else if (ftype==KexiDB::Field::DateTime) {
00433 QDateTime dt(v.toDateTime());
00434 if (dt.isValid())
00435 text = KGlobal::locale()->formatDateTime(dt);
00436 }
00438 else if (ftype==KexiDB::Field::Date) {
00439 QDate date(v.toDate());
00440 if (date.isValid())
00441 text = KGlobal::locale()->formatDate(date, true);
00442 }
00444 else if (ftype==KexiDB::Field::Time) {
00445 QTime time(v.toTime());
00446 if (time.isValid())
00447 text = KGlobal::locale()->formatTime(time);
00448 }
00450 else if (ci->field->isFPNumericType())
00451 text = KGlobal::locale()->formatNumber(v.toDouble());
00452 else if (ftype==KexiDB::Field::Boolean)
00453 text = v.toBool()
00454 ? i18n("Boolean Yes (true)","Yes") : i18n("Boolean No (false)", "No");
00455 else if (ftype==KexiDB::Field::BLOB) {
00456 const QByteArray ba( v.toByteArray() );
00457 if (!ba.isEmpty()) {
00458 QPixmap pixmap(ba);
00459 #define MAX_PIXMAP_HEIGHT (m_mainLineSpacing * 5)
00460 double pixmapHeight = MAX_PIXMAP_HEIGHT;
00461 double pixmapWidth = double(MAX_PIXMAP_HEIGHT) * pixmap.width() / (double)pixmap.height();
00462 if (pixmapWidth > (double)rect.width()) {
00463 pixmapHeight = pixmapHeight * (double)rect.width() / pixmapWidth;
00464 pixmapWidth = rect.width();
00465 }
00466 rect.setHeight( int( pixmapHeight + m_mainLineSpacing / 2 ) );
00467 if (paint && !pixmap.isNull()) {
00468 if (printing) {
00469 painter.drawPixmap(
00470 QRect(rect.x(), rect.y()+m_mainLineSpacing/4,
00471 int(pixmapWidth), int(pixmapHeight)), pixmap );
00472 }
00473 else {
00474
00475 painter.save();
00476 painter.setWindow(
00477 QRect(painter.window().topLeft(),
00478 painter.window().size() / (int)m_SCALE ) );
00479 painter.drawImage(
00480 int(rect.x() / m_SCALE),
00481 int( (rect.y()+m_mainLineSpacing/4) / m_SCALE),
00482 pixmap.convertToImage().smoothScale(
00483 int(pixmapWidth / m_SCALE), int(pixmapHeight / m_SCALE),
00484 QImage::ScaleMin ));
00485 painter.restore();
00486 }
00487 }
00488 }
00489 }
00490 else
00491 text = v.toString();
00492
00493 if (ftype!=KexiDB::Field::BLOB || v.isNull() || !v.isValid())
00494 rect = QRect( painter.fontMetrics().boundingRect(
00495 rect.x(), rect.y(), rect.width(), rect.height(),
00496 Qt::AlignAuto|Qt::WordBreak, text) );
00497 if (!text.isEmpty() && paint) {
00498
00499
00500
00501 painter.drawText(
00502
00503 rect.x(), rect.y(), m_pageWidth - m_maxFieldNameWidth - cellMargin*2,
00504 int(m_topMargin + m_pageHeight - (int)y),
00505 Qt::AlignTop|Qt::WordBreak, text);
00506 }
00507 if (m_settings->addTableBorders) {
00508 if (paint) {
00509 painter.setPen(Qt::darkGray);
00510 painter.drawLine(
00511 (int)m_leftMargin, rect.top(), (int)m_leftMargin+m_pageWidth-1, rect.top());
00512 painter.drawLine(
00513 (int)m_leftMargin, rect.top(), (int)m_leftMargin, rect.bottom());
00514 painter.drawLine(
00515 (int)m_leftMargin+m_pageWidth-1, rect.top(),
00516 (int)m_leftMargin+m_pageWidth-1, rect.bottom());
00517 painter.drawLine(
00518 (int)m_leftMargin+m_maxFieldNameWidth, rect.top(),
00519 (int)m_leftMargin+m_maxFieldNameWidth, rect.bottom());
00520 painter.setPen(Qt::black);
00521 }
00522 }
00523 y += (double)rect.height();
00524 }
00525 if (m_settings->addTableBorders) {
00526 if (paint) {
00527 painter.setPen(Qt::darkGray);
00528 painter.drawLine(
00529 (int)m_leftMargin, (int)y, (int)m_leftMargin+m_pageWidth-1, (int)y);
00530 painter.setPen(Qt::black);
00531 }
00532 }
00533
00534 y += double(m_mainLineSpacing)*3.0/2.0;
00535
00536
00537 }
00538
00539 void KexiSimplePrintingEngine::calculatePagesCount(QPainter& painter)
00540 {
00541 if (m_eof || !m_data) {
00542 m_pagesCount = 0;
00543 return;
00544 }
00545
00546 uint pageNumber = 0;
00547 for(;!m_eof; ++pageNumber) {
00548 paintPage(pageNumber, painter, false );
00549 }
00550 m_pagesCount = pageNumber;
00551 }
00552
00553 void KexiSimplePrintingEngine::setTitleText(const QString& titleText)
00554 {
00555 m_headerText = titleText;
00556 }
00557
00558 #include "kexisimpleprintingengine.moc"