kexi

kexisimpleprintingengine.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2005,2006 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this program; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
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 
00039 #include <kprinter.h>
00040 
00041 #include <kexiutils/tristate.h>
00042 #include <kexidb/connection.h>
00043 #include <kexidb/tableschema.h>
00044 #include <kexidb/cursor.h>
00045 #include <kexidb/utils.h>
00046 #include <kexidb/queryschema.h>
00047 
00048 KexiSimplePrintingSettings::KexiSimplePrintingSettings()
00049 {
00050     pageLayout = KoPageLayout::standardLayout();
00051     addPageNumbers = true;
00052     addDateAndTime = true;
00053     addTableBorders = false;
00054     pageTitleFont = kapp->font();
00055     pageTitleFont.setPointSizeFloat( (double)QFontInfo(pageTitleFont).pointSize()*1.5 );
00056     pageTitleFont.setBold(true);
00057 }
00058 
00059 KexiSimplePrintingSettings::~KexiSimplePrintingSettings()
00060 {
00061 }
00062 
00063 KexiSimplePrintingSettings KexiSimplePrintingSettings::load()
00064 {
00065     KexiSimplePrintingSettings settings; //this will set defaults
00066 
00067     KConfig *config = kapp->config();
00068     config->setGroup("Simple Printing");
00069     if (config->hasKey("pageTitleFont"))
00070         settings.pageTitleFont = config->readFontEntry("pageTitleFont");
00072     if (config->hasKey("pageFormat"))
00073         settings.pageLayout.format = KoPageFormat::formatFromString( 
00074             config->readEntry("pageFormat" ) );
00075     if (config->readEntry("pageOrientation", "portrait").lower()=="landscape")
00076         settings.pageLayout.orientation = PG_LANDSCAPE;
00077     else
00078         settings.pageLayout.orientation = PG_PORTRAIT;
00079     if (config->hasKey("pageWidth"))
00080         settings.pageLayout.ptWidth = config->readDoubleNumEntry("pageWidth");
00081     if (config->hasKey("pageHeight"))
00082         settings.pageLayout.ptHeight = config->readDoubleNumEntry("pageHeight");
00083     if (config->hasKey("pageLeftMargin"))
00084         settings.pageLayout.ptLeft = config->readDoubleNumEntry("pageLeftMargin");
00085     if (config->hasKey("pageRightMargin"))
00086         settings.pageLayout.ptRight = config->readDoubleNumEntry("pageRightMargin");
00087     if (config->hasKey("pageTopMargin"))
00088         settings.pageLayout.ptTop = config->readDoubleNumEntry("pageTopMargin");
00089     if (config->hasKey("pageBottomMargin"))
00090         settings.pageLayout.ptBottom = config->readDoubleNumEntry("pageBottomMargin");
00091     settings.addPageNumbers = config->readBoolEntry("addPageNumbersToPage", true);
00092     settings.addDateAndTime = config->readBoolEntry("addDateAndTimePage", true);
00093     settings.addTableBorders = config->readBoolEntry("addTableBorders", false);
00094     return settings;
00095 }
00096 
00097 void KexiSimplePrintingSettings::save()
00098 {
00099     KConfig *config = kapp->config();
00100     config->setGroup("Simple Printing");
00101     config->writeEntry( "pageTitleFont", pageTitleFont );
00102     config->writeEntry( "pageFormat", KoPageFormat::formatString( pageLayout.format ) );
00103     config->writeEntry("pageOrientation", 
00104         pageLayout.orientation == PG_PORTRAIT ? "portrait" : "landscape");
00105     config->writeEntry("pageWidth", pageLayout.ptWidth);
00106     config->writeEntry("pageHeight", pageLayout.ptHeight);
00107     config->writeEntry("pageLeftMargin", pageLayout.ptLeft);
00108     config->writeEntry("pageRightMargin", pageLayout.ptRight);
00109     config->writeEntry("pageTopMargin", pageLayout.ptTop);
00110     config->writeEntry("pageBottomMargin", pageLayout.ptBottom);
00111     config->writeEntry("addPageNumbersToPage", addPageNumbers);
00112     config->writeEntry("addDateAndTimePage", addDateAndTime);
00113     config->writeEntry("addTableBorders", addTableBorders);
00114     config->sync();
00115 }
00116 
00117 //------------------------
00118 
00119 KexiSimplePrintingEngine::KexiSimplePrintingEngine(
00120     const KexiSimplePrintingSettings& settings, QObject* parent)
00121  : QObject(parent, "KexiSimplePrintingEngine")
00122  , m_settings(&settings)
00123  , m_pdm(0)
00124 {
00125     m_cursor = 0;
00126     m_data = 0;
00127     m_visibleFieldsCount = 0;
00128     m_dataOffsets.setAutoDelete(true);
00129     clear();
00130 }
00131 
00132 KexiSimplePrintingEngine::~KexiSimplePrintingEngine()
00133 {
00134     done();
00135 }
00136 
00137 bool KexiSimplePrintingEngine::init(KexiDB::Connection& conn, 
00138     KexiDB::TableOrQuerySchema& tableOrQuery, const QString& titleText, QString& errorMessage)
00139 {
00140     errorMessage = QString::null;
00141     done();
00142     m_headerText = titleText; //tableOrQuery.captionOrName();
00143 
00144     //open data source
00145     KexiDB::QuerySchema *query = 0;
00146     if (tableOrQuery.table())
00147         query = tableOrQuery.table()->query(); //all rows
00148     else
00149         query = tableOrQuery.query();
00150     if (!query) {
00151         errorMessage = i18n("Could not load data from table or query.");
00152         return false;
00153     }
00154 
00155     m_cursor = conn.executeQuery(*query);
00156     if (!m_cursor) {
00157         conn.debugError();
00158         return false;
00159     }
00160     bool ok = !m_cursor->error();
00161     if (ok) {
00162         m_data = new KexiTableViewData(m_cursor);
00164         m_data->preloadAllRows();
00165         m_fieldsExpanded = query->fieldsExpanded( KexiDB::QuerySchema::WithInternalFields );
00166         m_visibleFieldsCount = m_cursor->query()->fieldsExpanded().count(); //real fields count without internals
00167     }
00168     else {
00169         conn.debugError();
00170     }
00171     m_eof = !ok || m_data->count() == 0;
00172     conn.deleteCursor(m_cursor);
00173     m_cursor = 0;
00174     return ok;
00175 }
00176 
00177 bool KexiSimplePrintingEngine::done()
00178 {
00179     bool result = true;
00180     if (m_cursor && (m_cursor->error() || !m_cursor->connection()->deleteCursor(m_cursor))) {
00181         m_cursor->debugError();
00182         result = false;
00183     }
00184     m_cursor = 0;
00185     delete m_data;
00186     m_data = 0;
00187     m_pagesCount = 0;
00188     m_paintInitialized = false;
00189     m_fieldsExpanded.clear();
00190     m_visibleFieldsCount = 0;
00191     return result;
00192 }
00193 
00194 void KexiSimplePrintingEngine::clear()
00195 {
00196     m_eof = false;
00197     m_pagesCount = 0;
00198     m_dataOffsets.clear();
00199     m_dataOffsets.append(new uint(0));
00200     m_paintInitialized = false;
00201 }
00202 
00203 void KexiSimplePrintingEngine::paintPage(int pageNumber, QPainter& painter, bool paint)
00204 {
00205     uint offset = 0;
00206     if (pageNumber < (int)m_dataOffsets.count()) {
00207         offset = *m_dataOffsets.at(pageNumber);
00208     }
00209 
00210     uint y = 0;
00211 
00212     const bool printer = painter.device()->devType() == QInternal::Printer;
00213 
00214     int w = 0, h = 0;
00215     m_pdm = QPaintDeviceMetrics( painter.device() );
00216     
00217     if (dynamic_cast<QWidget*>(painter.device())) {
00218         w = dynamic_cast<QWidget*>(painter.device())->width();
00219         h = dynamic_cast<QWidget*>(painter.device())->height();
00220     }
00221     else if (dynamic_cast<QPixmap*>(painter.device())) {
00222         w = dynamic_cast<QPixmap*>(painter.device())->width();
00223         h = dynamic_cast<QPixmap*>(painter.device())->height();
00224     }
00225     else {//KPrinter...
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 (!printer) {
00242 //          m_dpiY = 96;
00243 //          m_dpiX = 96;
00244             m_dpiY = 86;
00245             m_dpiX = 86;
00246         }
00247 #endif
00248         int pdWidthMM = m_pdm.widthMM();
00249         int pdHeightMM = m_pdm.heightMM();
00250 
00251         double screenF;
00252 //      if (printer)
00253             screenF = 1.0;
00254 //      else
00255 //          screenF = (double)96.0/120.0;
00256 
00257         leftMargin = POINT_TO_INCH(m_settings->pageLayout.ptLeft)*m_dpiX* screenF;
00258         rightMargin = POINT_TO_INCH(m_settings->pageLayout.ptRight)*m_dpiX* screenF;
00259         topMargin = POINT_TO_INCH(m_settings->pageLayout.ptTop)*m_dpiY* screenF;
00260         bottomMargin = POINT_TO_INCH(m_settings->pageLayout.ptBottom)*m_dpiY* screenF;
00261         
00262         m_fx = widthMM / (pdWidthMM * screenF);
00263         m_fy = heightMM / (pdHeightMM * screenF);
00264 
00265     //screen only
00266     //  painter.fillRect(QRect(0,0,w,h), QBrush(white));
00267         m_pageWidth = int( m_fx*(double)m_pdm.width() - leftMargin - rightMargin);
00268         m_pageHeight = int( m_fy*(double)m_pdm.height() - topMargin - bottomMargin);
00269         m_headerFont = m_settings->pageTitleFont;
00270         if(!printer) {
00271             int pixelSize = int( POINT_TO_INCH((double)QFontInfo(m_headerFont).pointSize())*m_dpiX );
00272             m_headerFont.setPixelSize(pixelSize);
00273         }
00274 
00276         m_mainFont = kapp->font(); 
00277         if(!printer) {
00278             int pixelSize = int( POINT_TO_INCH(m_mainFont.pointSizeFloat())*m_dpiX );
00279             m_mainFont.setPixelSize(pixelSize);
00280         }
00281         painter.setFont(m_mainFont);
00282 
00283         m_dateTimeText = KGlobal::locale()->formatDateTime(QDateTime::currentDateTime(),
00284             true, false);
00285         m_dateTimeWidth = painter.fontMetrics().width(m_dateTimeText+"   ");
00286         m_mainLineSpacing = painter.fontMetrics().lineSpacing();
00287         m_footerHeight = m_mainLineSpacing * 2; //2 lines
00288         painter.setFont(m_headerFont);
00289         m_headerTextRect = painter.fontMetrics().boundingRect(
00290             (int)leftMargin, (int)topMargin,
00291             m_pageWidth - m_dateTimeWidth,
00292             m_pageHeight, Qt::AlignAuto|Qt::WordBreak, m_headerText);
00293         m_headerTextRect.setRight(m_headerTextRect.right()+10);
00294         m_headerTextRect.setWidth(
00295             QMIN(int(m_pageWidth - m_dateTimeWidth), m_headerTextRect.width()));
00296 
00297         //--compute max width of field names
00298         m_maxFieldNameWidth = 0;
00299         
00300         painter.setFont(m_mainFont);
00301         for (uint i=0; i < m_visibleFieldsCount; i++) {
00302             const int newW =
00303                 painter.fontMetrics().width(m_fieldsExpanded[i]->captionOrAliasOrName()+":");
00304 //          kdDebug() << "row"<<i<<": "<<m_fieldsExpanded[i]->captionOrAliasOrName()<<" " 
00305 //              << newW <<endl;
00306             if (m_maxFieldNameWidth < newW)
00307                 m_maxFieldNameWidth = newW;
00308         }
00309         m_maxFieldNameWidth += painter.fontMetrics().width("ww"); //more space
00310     }
00311 
00312     //screen only
00313     if(!printer) {
00314         painter.setWindow(0, 0, int((double)w*m_fx), int((double)h*m_fy));
00315     }
00316 
00317     //paint header
00318     painter.setFont(m_headerFont);
00319     if (paint) {
00320         painter.drawText(m_headerTextRect, Qt::AlignAuto|Qt::WordBreak, m_headerText);
00321     }
00322     painter.setFont(m_mainFont);
00323     if (paint) {
00324         painter.drawText((int)leftMargin + m_pageWidth - m_dateTimeWidth, 
00325             (int)topMargin, m_dateTimeWidth, 
00326             m_headerTextRect.height(), Qt::AlignRight, m_dateTimeText);
00327         //footer
00328         
00329         QString pageNumString;
00330         if (m_pagesCount>0)
00331             pageNumString = i18n("Page (number) of (total)", "Page %1 of %2")
00332                 .arg(pageNumber+1).arg(m_pagesCount);
00333         else
00334             pageNumString = i18n("Page %1").arg(pageNumber+1);
00335         painter.drawText((int)leftMargin, 
00336             (int)topMargin + m_pageHeight - m_mainLineSpacing, 
00337             m_pageWidth, m_mainLineSpacing,
00338             Qt::AlignRight | Qt::AlignBottom, pageNumString);
00339         painter.drawLine((int)leftMargin, 
00340             (int)topMargin + m_pageHeight - m_mainLineSpacing*3/2, 
00341             (int)leftMargin + m_pageWidth,
00342             (int)topMargin + m_pageHeight - m_mainLineSpacing*3/2);
00343     }
00344     y = (int)topMargin + m_headerTextRect.height() + m_mainLineSpacing/2;
00345     if (!m_settings->addTableBorders) {
00346         //separator line
00347         if (paint)
00348             painter.drawLine((int)leftMargin, y, (int)leftMargin + m_pageWidth-1, y);
00349         y += m_mainLineSpacing;
00350     }
00351 
00352     //--print records
00353     KexiDB::RowData row;
00354     KexiTableItem *item;
00355 //  const uint count = m_fieldsExpanded.count();
00356 //  const uint count = m_cursor->query()->fieldsExpanded().count(); //real fields count without internals
00357     const uint rows = m_data->count();
00358     const int cellMargin = m_settings->addTableBorders ? 
00359         painter.fontMetrics().width("i") : 0;
00360     uint paintedRows = 0;
00361     for (;offset < rows; ++offset) {
00362         item = m_data->at(offset);
00363 
00364         //compute height of this record
00365         uint newY = y;
00366         paintRecord(painter, item, cellMargin, newY, paintedRows, false);
00367         if ((int(topMargin + m_pageHeight-(int)newY-m_footerHeight)) < 0 /*(1)*/ && paintedRows > 0/*(2)*/) {
00368             //(1) do not break records between pages
00369             //(2) but paint at least one record
00371             break;
00372         }
00373 /*      if (int(count * m_mainLineSpacing) > int(topMargin + m_pageHeight-(int)y-m_footerHeight)) 
00374         {
00375             //do not break records between pages
00376             break;
00377         }*/
00378 //      kdDebug() << " -------- " << y << " / " << m_pageHeight << endl;
00379         if (paint)
00380             paintRecord(painter, item, cellMargin, y, paintedRows, paint);
00381         else
00382             y = newY; //speedup
00383         paintedRows++;
00384     }
00385 
00386     if (int(m_dataOffsets.count()-1)==pageNumber) {//this was next page
00387         m_dataOffsets.append(new uint(offset));
00388     }
00389     m_eof = offset == rows;
00390 }
00391 
00392 void KexiSimplePrintingEngine::paintRecord(QPainter& painter, KexiTableItem *item, 
00393     int cellMargin, uint &y, uint paintedRows, bool paint)
00394 {
00395     if (paintedRows>0 && !m_settings->addTableBorders) {//separator
00396         if (paint) {
00397             painter.setPen(Qt::darkGray);
00398             painter.drawLine(
00399                 (int)leftMargin, y-m_mainLineSpacing, 
00400                 (int)leftMargin+m_pageWidth-1, y-m_mainLineSpacing);
00401             painter.setPen(Qt::black);
00402         }
00403     }
00404 
00405     for (uint i=0; i<m_visibleFieldsCount; i++) {
00406 //          kdDebug() << "row"<<i<<": "<<row.at(i).toString()<<endl;
00407         if (paint) {
00408             painter.drawText(
00409                 (int)leftMargin+cellMargin, y, m_maxFieldNameWidth-cellMargin*2, m_mainLineSpacing, 
00410                 Qt::AlignTop, m_fieldsExpanded[i]->captionOrAliasOrName()
00411                 + (m_settings->addTableBorders ? "" : ":"));
00412         }
00413         QString text;
00415         //get real column and real index to get the visible value
00416         KexiDB::QueryColumnInfo* ci;
00417         int indexForVisibleLookupValue = m_fieldsExpanded[i]->indexForVisibleLookupValue();
00418         if (-1 != indexForVisibleLookupValue && indexForVisibleLookupValue < (int)item->count()/*sanity*/)
00419             ci = m_fieldsExpanded[ indexForVisibleLookupValue ];
00420         else {
00421             ci = m_fieldsExpanded[ i ];
00422             indexForVisibleLookupValue = i;
00423         }
00424 
00425         QVariant v(item->at( indexForVisibleLookupValue ));
00426         KexiDB::Field::Type ftype = ci->field->type();
00427         if (v.isNull() || !v.isValid()) {
00428             //nothing to do
00429         }
00431         else if (ftype==KexiDB::Field::DateTime) {
00432             QDateTime dt(v.toDateTime());
00433             if (dt.isValid())
00434                 text = KGlobal::locale()->formatDateTime(dt);
00435         }
00437         else if (ftype==KexiDB::Field::Date) {
00438             QDate date(v.toDate());
00439             if (date.isValid())
00440                 text = KGlobal::locale()->formatDate(date, true/*short*/);
00441         }
00443         else if (ftype==KexiDB::Field::Time) {
00444             QTime time(v.toTime());
00445             if (time.isValid())
00446                 text = KGlobal::locale()->formatTime(time);
00447         }
00449         else if (ci->field->isFPNumericType())
00450             text = KGlobal::locale()->formatNumber(v.toDouble());
00451         else if (ftype==KexiDB::Field::Boolean)
00452             text = v.toBool() 
00453                 ? i18n("Boolean Yes (true)","Yes") : i18n("Boolean No (false)", "No");
00454         else
00455             text = v.toString();
00456         QRect rect( painter.fontMetrics().boundingRect(
00457             (int)leftMargin + m_maxFieldNameWidth + cellMargin, y,
00458             m_pageWidth - m_maxFieldNameWidth - cellMargin*2, m_pageHeight - y, 
00459             Qt::AlignAuto|Qt::WordBreak, text) );
00460         if (paint) {
00461             painter.drawText(
00462                 rect.x(), rect.y(), rect.width(), rect.height(),
00463                 Qt::AlignTop|Qt::WordBreak, text);
00464         }
00465         if (m_settings->addTableBorders) {
00466             if (paint) {
00467                 painter.setPen(Qt::darkGray);
00468                 painter.drawLine(
00469                     (int)leftMargin, rect.top(), (int)leftMargin+m_pageWidth-1, rect.top());
00470                 painter.drawLine(
00471                     (int)leftMargin, rect.top(), (int)leftMargin, rect.bottom());
00472                 painter.drawLine(
00473                     (int)leftMargin+m_pageWidth-1, rect.top(), 
00474                     (int)leftMargin+m_pageWidth-1, rect.bottom());
00475                 painter.drawLine(
00476                     (int)leftMargin+m_maxFieldNameWidth, rect.top(), 
00477                     (int)leftMargin+m_maxFieldNameWidth, rect.bottom());
00478                 painter.setPen(Qt::black);
00479             }
00480         }
00481         y += rect.height();
00482     }
00483     if (m_settings->addTableBorders) {
00484         if (paint) {
00485             painter.setPen(Qt::darkGray);
00486             painter.drawLine(
00487                 (int)leftMargin, y, (int)leftMargin+m_pageWidth-1, y);
00488             painter.setPen(Qt::black);
00489         }
00490     }
00491     //record spacing
00492     y += m_mainLineSpacing*3/2;
00493 //  if (m_settings->addTableBorders)
00494 //      y -= m_mainLineSpacing; //a bit less
00495 }
00496 
00497 void KexiSimplePrintingEngine::calculatePagesCount(QPainter& painter)
00498 {
00499     if (m_eof || !m_data) {
00500         m_pagesCount = 0;
00501         return;
00502     }
00503 
00504     uint pageNumber = 0;
00505     for(;!m_eof; ++pageNumber) {
00506         paintPage(pageNumber, painter, false /* !paint */);
00507     }
00508     m_pagesCount = pageNumber;
00509 }
00510 
00511 void KexiSimplePrintingEngine::setTitleText(const QString& titleText)
00512 {
00513     m_headerText = titleText;
00514 }
00515 
00516 #include "kexisimpleprintingengine.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys