QSizeF ChartTextObject::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) { Q_UNUSED(posInDocument); QSizeF size( format.property( Size ).toSizeF() ); switch ( format.property( Unit ).toInt() ) { case Percent: { const qreal pageWidth = doc->pageSize().width(); const qreal percent = size.width(); const qreal ratio = size.height() / size.width(); qreal newWidth = pageWidth * percent / 100.0; //XXX For some reason 100% width charts will get cropped //need to make a little room if ( percent == 100.0 ) newWidth -= 9; return QSizeF( newWidth, newWidth * ratio ); } case Millimeters: return QSizeF( mmToPixels( size.width() ), mmToPixels( size.height() ) ); } return QSizeF(); }
qreal KDReports::ReportPrivate::mainTextDocHeight() const { const qreal height = rawMainTextDocHeight(); const bool skip = height <= 0; if ( skip ) { qreal textDocHeight = paperSize().height() - mmToPixels( m_marginTop + m_marginBottom ); textDocHeight -= mmToPixels( m_headerBodySpacing ); textDocHeight -= mmToPixels( m_footerBodySpacing ); return textDocHeight; } return height; }
// The height of the text doc, by calculation. Adjusted by caller, if negative. qreal KDReports::ReportPrivate::rawMainTextDocHeight() const { qreal textDocHeight = paperSize().height() - mmToPixels( m_marginTop + m_marginBottom ); const qreal headerHeight = m_headers.height(); textDocHeight -= headerHeight; textDocHeight -= mmToPixels( m_headerBodySpacing ); const qreal footerHeight = m_footers.height(); textDocHeight -= mmToPixels( m_footerBodySpacing ); textDocHeight -= footerHeight; //qDebug() << "pageContent height (pixels): paper size" << m_paperSize.height() << "minus margins" << mmToPixels( m_marginTop + m_marginBottom ) // << "minus headerHeight" << headerHeight << "minus footerHeight" << footerHeight << "and spacings =" << textDocHeight; return textDocHeight; }
void KDReports::Frame::build( ReportBuilder& builder ) const { // prepare the frame QTextFrameFormat format; if ( d->m_width ) { if ( d->m_widthUnit == Millimeters ) { format.setWidth( QTextLength( QTextLength::FixedLength, mmToPixels( d->m_width ) ) ); } else { format.setWidth( QTextLength( QTextLength::PercentageLength, d->m_width ) ); } } if ( d->m_height ) { if ( d->m_heightUnit == Millimeters ) { format.setHeight( QTextLength( QTextLength::FixedLength, mmToPixels( d->m_height ) ) ); } else { format.setHeight( QTextLength( QTextLength::PercentageLength, d->m_height ) ); } } format.setPadding( mmToPixels( padding() ) ); format.setBorder( d->m_border ); // TODO borderBrush like in AbstractTableElement format.setPosition( QTextFrameFormat::InFlow ); QTextCursor& textDocCursor = builder.cursor(); QTextFrame *frame = textDocCursor.insertFrame(format); QTextCursor contentsCursor = frame->firstCursorPosition(); ReportBuilder contentsBuilder( builder.currentDocumentData(), contentsCursor, builder.report() ); contentsBuilder.copyStateFrom( builder ); foreach( const KDReports::ElementData& ed, d->m_elements ) { switch ( ed.m_type ) { case KDReports::ElementData::Inline: contentsBuilder.addInlineElement( *ed.m_element ); break; case KDReports::ElementData::Block: contentsBuilder.addBlockElement( *ed.m_element, ed.m_align ); break; case KDReports::ElementData::Variable: contentsBuilder.addVariable( ed.m_variableType ); break; } } textDocCursor.movePosition( QTextCursor::End ); }
bool KDReports::Report::exportToImage( const QSize& size, const QString& fileName, const char* format ) { // Get the document to fit into one page QPrinter::PageSize savePageSize = pageSize(); const qreal saveLayoutWidth = d->m_layoutWidth; d->m_layoutWidth = d->m_layout->idealWidth() + mmToPixels(d->m_marginLeft + d->m_marginRight); d->m_pageContentSizeDirty = true; d->ensureLayouted(); const qreal zoomFactor = qMin( (qreal)size.width() / d->m_paperSize.width(), (qreal)size.height() / d->m_paperSize.height() ); //qDebug() << "zoomFactor=" << zoomFactor; QImage image( size, QImage::Format_ARGB32_Premultiplied ); image.fill( Qt::white ); QPainter painter( &image ); painter.setRenderHint( QPainter::Antialiasing ); painter.setRenderHint( QPainter::SmoothPixmapTransform ); painter.fillRect( QRectF(0, 0, size.width(), size.height()), QBrush(Qt::white) ); painter.scale( zoomFactor, zoomFactor ); d->paintPage( 0, painter ); // restore textdoc size and header widths d->m_layoutWidth = saveLayoutWidth; setPageSize( savePageSize ); // redo layout qDebug() << "Saving pixmap" << image.size() << "into" << fileName << "with format" << format; return image.save( fileName, format ); }
QSizeF KDReports::ReportPrivate::paperSize() const { // determine m_paperSize from m_pageSize if needed if (m_paperSize.isEmpty()) { int width_index = 0; int height_index = 1; if (m_orientation == QPrinter::Landscape) { width_index = 1; height_index = 0; } m_paperSize = QSizeF(mmToPixels(kdr_paperSizes[m_pageSize][width_index]), mmToPixels(kdr_paperSizes[m_pageSize][height_index])); } //qDebug() << "m_paperSize=" << m_paperSize; return m_paperSize; }
QSizeF KDReports::ReportPrivate::layoutAsOnePage( qreal docWidth ) { m_headers.layoutWithTextWidth( docWidth ); m_footers.layoutWithTextWidth( docWidth ); const qreal docHeight = m_layout->layoutAsOnePage(docWidth); qreal pageWidth = docWidth + mmToPixels( m_marginLeft + m_marginRight ); qreal pageHeight = docHeight + mmToPixels( m_marginTop + m_marginBottom ); pageHeight += m_headers.height(); pageHeight += m_footers.height(); m_pageContentSizeDirty = false; //qDebug() << "One-page document is" << pageWidth << "x" << pageHeight; return QSizeF( pageWidth, pageHeight ); }
void KDReports::Report::setWidthForEndlessPrinter( qreal widthMM ) { if ( widthMM ) { d->m_endlessPrinterWidth = widthMM; d->m_layoutWidth = mmToPixels( widthMM ); d->m_pageContentSizeDirty = true; d->ensureLayouted(); } else { d->m_layoutWidth = 0; d->m_pageContentSizeDirty = true; // caller will call setPageSize... } }
void KDReports::AbstractTableElement::fillTableFormat( QTextTableFormat& tableFormat, QTextCursor& textDocCursor ) const { if ( d->m_width ) { if ( d->m_unit == Millimeters ) { tableFormat.setWidth( QTextLength( QTextLength::FixedLength, mmToPixels( d->m_width ) ) ); } else { tableFormat.setWidth( QTextLength( QTextLength::PercentageLength, d->m_width ) ); } } tableFormat.setBorder( border() ); #if QT_VERSION >= 0x040300 tableFormat.setBorderBrush( borderBrush() ); tableFormat.setBorderStyle( QTextFrameFormat::BorderStyle_Solid ); #endif tableFormat.setCellPadding( mmToPixels( padding() ) ); tableFormat.setCellSpacing( -1 ); // HTML-like table borders look so old century if ( d->m_fontSpecified ) { QTextCharFormat charFormat = textDocCursor.charFormat(); charFormat.setFont( d->m_defaultFont ); textDocCursor.setCharFormat( charFormat ); } }
void KDReports::Report::setPaperSize( const QSizeF & paperSize, QPrinter::Unit unit ) { qreal factor = 1.0; switch ( unit ) { case QPrinter::DevicePixel: break; case QPrinter::Millimeter: factor = mmToPixels( 1.0 ); break; case QPrinter::Point: factor = 72.0 * qt_defaultDpi(); break; case QPrinter::Inch: factor = qt_defaultDpi(); break; default: qWarning( "Unsupported printer unit %d", unit ); } d->m_paperSize = QSizeF( paperSize.width() * factor, paperSize.height() * factor ); d->m_pageContentSizeDirty = true; }
/* [top margin] [header] [m_headerBodySpacing] [body] [m_footerBodySpacing] [footer] [bottom margin] */ void KDReports::ReportPrivate::setPaperSizeFromPrinter( const QSizeF& paperSize ) { Q_ASSERT( !wantEndlessPrinting() ); // call ensureLayouted instead! m_paperSize = paperSize; const qreal marginsInPixels = mmToPixels( m_marginLeft + m_marginRight ); qreal textDocWidth = m_paperSize.width() - marginsInPixels; m_headers.layoutWithTextWidth( textDocWidth ); m_footers.layoutWithTextWidth( textDocWidth ); const qreal textDocHeight = mainTextDocHeight(); // Font scaling // Problem: how to re-implement this without a layout document? // We would risk cumulating rounding problems...? // ### 2nd problem: what about fonts in headers and footers? shouldn't they scale too? //if ( m_scaleFontsBy != 1.0 ) // m_textDocument.scaleFontsBy( m_scaleFontsBy ); m_layout->setPageContentSize( QSizeF( textDocWidth, textDocHeight ) ); m_pageContentSizeDirty = false; }
void KDReports::ReportPrivate::ensureLayouted() { // We need to do a layout if // m_pageContentSizeDirty is true, i.e. page size has changed etc. if (m_pageContentSizeDirty) { if (!wantEndlessPrinting()) { setPaperSizeFromPrinter(paperSize()); } else { // Get the document to fit into one page Q_ASSERT(m_layoutWidth != 0); qreal textDocWidth = m_layoutWidth - mmToPixels(m_marginLeft + m_marginRight); m_paperSize = layoutAsOnePage(textDocWidth); qDebug() << "setPaperSizeFromPrinter: endless printer. m_layoutWidth=" << m_layoutWidth << "textDocWidth=" << textDocWidth << "single page has size" << m_paperSize << "pixels"; Q_ASSERT(m_layout->numberOfPages() == 1); } // at this point m_pageContentSizeDirty has been set to false in all cases } m_layout->ensureLayouted(); }
qreal KDReports::ReportPrivate::textDocumentWidth() const { return paperSize().width() - mmToPixels( m_marginLeft + m_marginRight ); }
void KDReports::ReportPrivate::paintPage( int pageNumber, QPainter& painter ) { ensureLayouted(); const int pageCount = m_layout->numberOfPages(); KDReports::Header* header = m_headers.headerForPage( pageNumber + 1, pageCount ); if ( header ) { header->preparePaintingPage( pageNumber + m_firstPageNumber - 1 ); } KDReports::Header* footer = m_footers.headerForPage( pageNumber + 1, pageCount ); if ( footer ) { footer->preparePaintingPage( pageNumber + m_firstPageNumber - 1 ); } const qreal textDocWidth = m_paperSize.width() - mmToPixels( m_marginLeft + m_marginRight ); const qreal textDocHeight = mainTextDocHeight(); const int left = qRound( mmToPixels( m_marginLeft ) ); const int top = qRound( mmToPixels( m_marginTop ) ); //const int right = qRound( mmToPixels( m_marginRight ) ); const int bottom = qRound( mmToPixels( m_marginBottom ) ); const bool skipHeadersFooters = this->skipHeadersFooters(); const int headerHeightWithSpacing = qRound( ( skipHeadersFooters ? 0 : m_headers.height() ) + mmToPixels( m_headerBodySpacing ) ); const int footerHeight = skipHeadersFooters ? 0 : qRound( m_footers.height() ); //const int footerHeightWithspacing = qRound( m_footers.height() + mmToPixels( m_footerBodySpacing ) ); //const QRect paperRect( 0, 0, qRound( m_paperSize.width() ), qRound( m_paperSize.height() ) ); //const QRect textDocRect = paperRect.adjusted( left, top + headerHeightWithSpacing, // -right, - bottom - footerHeightWithspacing); const QRect textDocRect( left, top + headerHeightWithSpacing, textDocWidth, textDocHeight ); /*qDebug() << "paintPage: in pixels: top=" << top << " headerHeight=" << headerHeightWithSpacing << " textDoc size:" << textDocRect.size() << " bottom=" << bottom << " footerHeight=" << footerHeight;*/ if( !m_watermarkText.isEmpty() ) { painter.save(); painter.translate( textDocRect.center() ); painter.rotate( m_watermarkRotation ); painter.setFont( m_watermarkFont ); painter.setPen( m_watermarkColor ); const QSize textSize( painter.fontMetrics().size( Qt::TextSingleLine, m_watermarkText ) ); const QRect textRect( -textSize.width() / 2, -textSize.height()/2, textSize.width(), textSize.height() ); painter.drawText( textRect, Qt::AlignCenter, m_watermarkText ); painter.restore(); } if( !m_watermarkImage.isNull() ) { // We paint it without scaling it, for better quality. // But this means the actual size depends on the zoom level or printer resolution... // // It also means the image could end up being bigger than the page, and we don't want that. // So we scale down if necessary. But never up. QImage img = m_watermarkImage; if ( m_watermarkImage.width() > textDocRect.width() || m_watermarkImage.height() > textDocRect.height() ) { // should probably be cached? img = m_watermarkImage.scaled( textDocRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation ); } const QRect imageRect = QStyle::alignedRect( Qt::LeftToRight, Qt::AlignCenter, img.size(), textDocRect ); //qDebug() << "textDocRect=" << textDocRect << "size=" << img.size() << "-> imageRect=" << imageRect; painter.drawImage( imageRect.topLeft(), img ); } painter.save(); //painter.setClipRect( textDocRect, Qt::IntersectClip ); // triggers a Qt-Windows bug when printing painter.setClipRect( textDocRect ); painter.translate( left, top + headerHeightWithSpacing ); m_layout->paintPageContent( pageNumber, painter ); painter.restore(); QAbstractTextDocumentLayout::PaintContext ctx; ctx.palette.setColor(QPalette::Text, Qt::black); if ( header && !skipHeadersFooters ) { painter.save(); painter.translate( left, top ); ctx.clip = painter.clipRegion().boundingRect(); header->doc().contentDocument().documentLayout()->draw(&painter, ctx); painter.restore(); } if ( footer && !skipHeadersFooters ) { painter.save(); painter.translate( left, m_paperSize.height() - bottom - footerHeight ); ctx.clip = painter.clipRegion().boundingRect(); footer->doc().contentDocument().documentLayout()->draw(&painter, ctx); painter.restore(); } }
void KDReports::Report::setFixedRowHeight(qreal mm) { d->m_layout->setFixedRowHeight( mmToPixels(mm) ); }