bool TestXmlElementHandlerV1::textElement( KDReports::TextElement& textElement, QDomElement& xmlElement )
{
    Q_UNUSED( textElement );
    Q_UNUSED( xmlElement ); // unused in release mode
    Q_ASSERT( xmlElement.tagName() == "text" );
    cb << "textElement";
    if (textElement.id() == "testModification")
        textElement.setId("testModified");
    return true;
}
Exemple #2
0
bool KDReports::XmlParser::processNode( const QDomNode& node, KDReports::ReportBuilder* builder, bool inHeader, bool inFooter )
{
    // Loop over elements
    for ( QDomElement element = node.firstChildElement() ; !element.isNull();
          element = element.nextSiblingElement() ) {

        if ( testForErrorAndFillErrorDetails() )
            return false;

        const QString name = element.tagName();
        if( name == QLatin1String( "text" ) ) {
            // Handle <text> element
            KDReports::TextElement textElement;
            QString id;
            const QString text = extractText( element, &id, m_report->d->m_currentModel, m_report->d->m_currentRow );
            textElement.setText( text );
            textElement.setId( id );
            const QColor bgColor = KDReports::XmlHelper::readBackground( element );
            if( bgColor.isValid() )
                textElement.setBackground( bgColor );
            if( element.hasAttribute( QLatin1String( "pointsize" ) ) ) {
                const int pointSize = element.attribute( QLatin1String( "pointsize" ) ).toInt();
                if( pointSize )
                    textElement.setPointSize( pointSize );
            }
            if( element.hasAttribute( QLatin1String( "color" ) ) ) {
                const QString name = element.attribute( QLatin1String( "color" ) );
                textElement.setTextColor( QColor( name ) );
            }
            if( element.hasAttribute( QLatin1String( "font" ) ) ) {
                textElement.setFontFamily( element.attribute( QLatin1String( "font" ) ) );
            }
            if( element.hasAttribute( QLatin1String( "bold" ) ) ) {
                bool bold = false;
                if( element.attribute( QLatin1String( "bold" ) ) == QLatin1String( "true" ) )
                    bold = true;
                textElement.setBold( bold );
            }
            if( element.hasAttribute( QLatin1String( "italic" ) ) ) {
                bool italic = false;
                if( element.attribute( QLatin1String( "italic" ) ) == QLatin1String( "true" ) )
                    italic = true;
                textElement.setItalic( italic );
            }
            if( element.hasAttribute( QLatin1String( "strikeout" ) ) ) {
                bool strikeOut = false;
                if( element.attribute( QLatin1String( "strikeout" ) ) == QLatin1String( "true" ) )
                    strikeOut = true;
                textElement.setStrikeOut( strikeOut );
            }
            if( element.hasAttribute( QLatin1String( "underline" ) ) ) {
                bool underline = false;
                if( element.attribute( QLatin1String( "underline" ) ) == QLatin1String( "true" ) )
                    underline = true;
                textElement.setUnderline( underline );
            }

            const QString oldId = textElement.id();

            if ( m_xmlElementHandler && !m_xmlElementHandler->textElement( textElement, element ) )
                continue;

            if ( textElement.id() != oldId ) {
                // The handler modified the text element's id, look up the value again.
                const QHash<QString, QString>::const_iterator it = m_textValues.constFind( textElement.id() );
                if ( it != m_textValues.constEnd() ) {
                    textElement.setText( *it );
                }
            }

            if ( !builder ) {
                error( QObject::tr( "<text> is only supported in WordProcessing mode" ) );
            } else {
                if( element.hasAttribute( QLatin1String( "inline" ) ) ) {
                    builder->addInlineElementPublic( textElement );
                } else {
                    Qt::AlignmentFlag alignment = Qt::AlignLeft;
                    if( element.hasAttribute( QLatin1String( "alignment" ) ) )
                        alignment = KDReports::XmlHelper::stringToAlignment( element.attribute( QLatin1String( "alignment" ) ) );
                    const QColor bgColor = KDReports::XmlHelper::readColor( element, "paragraph-background" );
                    builder->addBlockElementPublic( textElement, alignment, bgColor );
                }
            }

        } else if( name == QLatin1String( "html" ) ) {
            // Handle <html> element
            KDReports::HtmlElement htmlElement;
            QString id;
            const QString text = extractText( element, &id );
            htmlElement.setHtml( text );
            htmlElement.setId( id );
            QColor bgColor = KDReports::XmlHelper::readBackground( element );
            if( bgColor.isValid() )
                htmlElement.setBackground( bgColor );

            const QString oldId = htmlElement.id();

            if ( m_xmlElementHandler && !m_xmlElementHandler->htmlElement( htmlElement, element ) )
                continue;

            if ( htmlElement.id() != oldId ) {
                // The handler modified the text element's id, look up the value again.
                const QHash<QString, QString>::const_iterator it = m_textValues.constFind( htmlElement.id() );
                if ( it != m_textValues.constEnd() ) {
                    htmlElement.setHtml( *it );
                }
            }

            addElement( htmlElement, builder, element );

        } else if ( name == QLatin1String( "tabs" ) ) {

            if ( !builder ) {
                error( QObject::tr( "<tabs> is only supported in WordProcessing mode" ) );
            } else {
                parseTabs( builder, element );
            }

        } else if ( name == QLatin1String( "paragraph-margins" ) ) {

            if ( !builder ) {
                error( QObject::tr( "<paragraph-margins> is only supported in WordProcessing mode" ) );
            } else {
                parseParagraphMargins( builder, element );
            }

        } else if( name == QLatin1String( "hr" ) ) {
            // Handle <hr> element
            KDReports::HtmlElement htmlElement;
            htmlElement.setHtml( QString::fromLatin1("<hr>") );
            if ( m_xmlElementHandler && !m_xmlElementHandler->htmlElement( htmlElement, element ) )
                continue;

            addElement( htmlElement, builder, element );

        } else if( name == QLatin1String( "vspace" ) ) {
            // Handle <vspace> element
            if( !element.hasAttribute( QLatin1String( "size" ) ) )
                continue; // size attribute is mandatory for VSpace
            int size = element.attribute( QLatin1String( "size" ) ).toInt();
            if ( !builder ) {
                error( QObject::tr( "<vspace> is only supported in WordProcessing mode" ) );
            } else {
                if( builder != m_report->d->builder() ) {
                    error( QObject::tr("<vspace> not allowed in headers, footers, or table cells") );
                    return false;
                }
            }
            XmlElementHandlerV2* v2 = dynamic_cast<XmlElementHandlerV2 *>(m_xmlElementHandler);
            if (v2 && !v2->vspace(size, element))
                continue;
            m_report->addVerticalSpacing( size );
        } else if( name == QLatin1String( "table" ) ) {
            // Handle <table> element
            const QString model = element.attribute( QLatin1String( "model" ) );
            if ( model.isEmpty() ) {
                if ( !builder ) {
                    error( QObject::tr( "<table> without a model is only supported in WordProcessing mode" ) );
                    continue;
                }
                KDReports::TableElement tableElement;
                const int headerRowCount = element.attribute( QLatin1String( "headerRowCount" ) ).toInt(); // default 0
                tableElement.setHeaderRowCount( headerRowCount );
                if ( element.hasAttribute( QLatin1String( "cellpadding" ) ) )
                    tableElement.setPadding( element.attribute( QLatin1String( "cellpadding" ) ).toInt() );
                parseCommonTableAttributes( tableElement, element );

                if ( m_xmlElementHandler && !m_xmlElementHandler->startTableElement( tableElement, element ) )
                    continue;

                if ( !parseTableContents( tableElement, element, *builder, inHeader, inFooter ) )
                    return false;

                if ( m_xmlElementHandler && !m_xmlElementHandler->endTableElement( tableElement, element ) )
                    continue;

                addElement( tableElement, builder, element );

            } else {
                KDReports::AutoTableElement tableElement( model );
                if( element.attribute( QLatin1String( "verticalHeaderVisible" ) ) == QLatin1String( "false" ) )
                    tableElement.setVerticalHeaderVisible(false);
                if( element.attribute( QLatin1String( "horizontalHeaderVisible" ) ) == QLatin1String( "false" ) )
                    tableElement.setHorizontalHeaderVisible(false);
                QColor headerBgColor = KDReports::XmlHelper::readColor( element, "header-background" );
                if ( headerBgColor.isValid() )
                    tableElement.setHeaderBackground( headerBgColor );
                parseCommonTableAttributes( tableElement, element );
                if ( m_xmlElementHandler && !m_xmlElementHandler->autoTableElement( tableElement, element ) )
                    continue;

                if ( m_report->reportMode() == Report::SpreadSheet ) {
                    m_report->mainTable()->setAutoTableElement( tableElement );
                } else {
                    addElement( tableElement, builder, element );
                }
            }
        } else if( name == QLatin1String( "chart" ) ) {
            // Handle <chart> element

            KDReports::ChartElement chartElement( element.attribute( QLatin1String( "model" ) ) );
            QColor bgColor = KDReports::XmlHelper::readBackground( element );
            if( bgColor.isValid() )
                chartElement.setBackground( bgColor );
            int width = 100, height = 100;
            Unit unit = Millimeters;
            if( element.hasAttribute( QLatin1String( "width" ) ) ) {
                QString str = element.attribute( QLatin1String( "width" ) );
                if ( str.endsWith( QLatin1Char('%') ) ) {
                    str.chop( 1 );
                    unit = Percent;
                }
                width = str.toInt();
            }
            if( element.hasAttribute( QLatin1String( "height" ) ) ) {
                QString str = element.attribute( QLatin1String( "height" ) );
                if ( str.endsWith( QLatin1Char('%') ) ) {
                    str.chop( 1 );
                    unit = Percent;
                }
                height = str.toInt();
            }
            chartElement.setSize( width, height, unit );

            if ( m_xmlElementHandler && !m_xmlElementHandler->chartElement( chartElement, element ) )
                continue;

            addElement( chartElement, builder, element );

        } else if( name == QLatin1String( "image" ) ) {
            // Handle <image> element

            QString id;
            QImage image = extractImage( element, &id );
            KDReports::ImageElement imageElement( image );
            imageElement.setId(id);
            if( element.hasAttribute( QLatin1String( "width" ) ) ) {
                QString widthStr = element.attribute( QLatin1String( "width" ) );
                if ( widthStr.endsWith( QLatin1Char('%') ) ) {
                    widthStr.truncate( widthStr.length() - 1 );
                    imageElement.setWidth( widthStr.toInt(), KDReports::Percent );
                } else {
                    imageElement.setWidth( widthStr.toInt() );
                }
            } else if( element.hasAttribute( QLatin1String( "height" ) ) ) { // mutually exclusive with "width"!
                QString heightStr = element.attribute( QLatin1String( "height" ) );
                if ( heightStr.endsWith( QLatin1Char('%') ) ) {
                    heightStr.truncate( heightStr.length() - 1 );
                    imageElement.setHeight( heightStr.toInt(), KDReports::Percent );
                } else {
                    imageElement.setHeight( heightStr.toInt() );
                }
            } else if ( element.hasAttribute( QLatin1String( "fitToPage" ) ) ) {
                imageElement.setFitToPage();
            }

            if ( m_xmlElementHandler && !m_xmlElementHandler->imageElement( imageElement, element ) )
                continue;

            addElement( imageElement, builder, element );

        } else if( name == QLatin1String( "header" ) ) {
            const KDReports::HeaderLocations loc = KDReports::XmlHelper::parseHeaderLocation( element.attribute( QLatin1String( "location" ) ) );
            KDReports::Header& header = m_report->header( loc );
            parseHeaderFooterAttribute( header, element );
            if ( m_xmlElementHandler && !m_xmlElementHandler->startHeader( header, element ) )
                continue;
            if( !processNode( element, &header.d->m_builder, true, false ) )
                return false;
            if ( m_xmlElementHandler )
                m_xmlElementHandler->endHeader( header, element );
        } else if( name == QLatin1String( "footer" ) ) {
            const KDReports::HeaderLocations loc = KDReports::XmlHelper::parseHeaderLocation( element.attribute( QLatin1String( "location" ) ) );
            KDReports::Footer& footer = m_report->footer( loc );
            parseHeaderFooterAttribute( footer, element );
            if ( m_xmlElementHandler && !m_xmlElementHandler->startFooter( footer, element ) )
                continue;
            if( !processNode( element, &footer.d->m_builder, false, true ) )
                return false;
            if ( m_xmlElementHandler )
                m_xmlElementHandler->endFooter( footer, element );
        } else if( name == QLatin1String( "variable" ) ) {
            if( !inHeader && !inFooter ) {
                error( QObject::tr("<variable> tags only allowed in headers and footers") );
                return false;
            }
            if( !element.hasAttribute( QLatin1String( "type" ) ) ) {
                error( QObject::tr("<variable> tags must have a 'type' attribute") );
                return false;
            }
            Q_ASSERT( builder );
            if ( builder ) {
                const QString type = element.attribute( QLatin1String( "type" ) );
                KDReports::VariableType vt = KDReports::XmlHelper::stringToVariableType( type );
                XmlElementHandlerV2* v2 = dynamic_cast<XmlElementHandlerV2 *>(m_xmlElementHandler);
                if (v2  && !v2->variable(vt, element))
                    continue;
                builder->addVariablePublic( vt );
            }
        } else if ( name == QLatin1String( "page-break" ) ) {
            if ( m_xmlElementHandler && !m_xmlElementHandler->pageBreak( element ) )
                continue;
            m_report->addPageBreak();
        } else if ( name == QLatin1String( "ifdef" ) ) {
            if ( element.hasAttribute( QLatin1String( "id" ) ) ) {
                const QString id = element.attribute( QLatin1String( "id" ) );
                const bool skip = m_textValues.value( id ).isEmpty();
                if( !skip ) {
                    if ( !processNode( element, builder, inHeader, inFooter ) )
                        return false;
                }
            }
        } else if ( name == QLatin1String( "custom" ) ) {
            if ( m_xmlElementHandler )
                m_xmlElementHandler->customElement( element );
        } else if ( name == QLatin1String( "hline" ) ) {
            KDReports::HLineElement hLineElement;

            if ( element.hasAttribute( QLatin1String( "thickness" ) ) ) {
                const double thickness = element.attribute( QLatin1String( "thickness" ) ).toDouble();
                hLineElement.setThickness( thickness );
            }

            if ( element.hasAttribute( QLatin1String( "color" ) ) ) {
                const QColor color = KDReports::XmlHelper::readColor( element, "color" );
                hLineElement.setColor( color );
            }

            if ( element.hasAttribute( QLatin1String( "margin" ) ) ) {
                const int margin = element.attribute( QLatin1String( "margin" ) ).toInt();
                hLineElement.setMargin( margin );
            }

#ifdef KDREPORTS_ALLOW_BINARY_INCOMPATIBILITY
            if ( m_xmlElementHandler && !m_xmlElementHandler->hLineElement( hLineElement, element ) )
               continue;
#else
            XmlElementHandlerV2* v2 = dynamic_cast<XmlElementHandlerV2 *>(m_xmlElementHandler);
            if (v2  && !v2->hLineElement(hLineElement, element))
                continue;
#endif

            addElement( hLineElement, builder, element );
        } else {
            error( QObject::tr( "KDReports::Report::loadFromXML(): Unknown element %1" ).arg( name ) );
        }
    }

    if ( testForErrorAndFillErrorDetails() )
        return false;

    return true;
}
int main( int argc, char** argv ) {
    QApplication app( argc, argv );

    KDReports::Report report;

    report.setHeaderBodySpacing( 10 ); // mm
    report.setFooterBodySpacing( 10 ); // mm

//     report.setWatermarkPixmap( QPixmap( ":/kdab.jpg" ) );
//     report.setWatermarkText( QString::null );

    KDReports::Header& header = report.header( KDReports::OddPages );
    QPixmap kdab( ":/kdab_small.jpg" );
    // add a border around the pixmap, mostly for debugging
    //QPainter painter( &kdab );
    //painter.drawRect( 0, 0, kdab.width() - 1, kdab.height() - 1 );
    KDReports::ImageElement imageElement( kdab );
    // The image size can be set in mm or in percent of the page width (without margins)
    // imageElement.setWidth( 50 ); // mm
    imageElement.setWidth( 40, KDReports::Percent );

    header.addElement( imageElement );
    header.addVariable( KDReports::PageNumber );
    header.addInlineElement( KDReports::TextElement( " / " ) );
    header.addVariable( KDReports::PageCount );
    header.addInlineElement( KDReports::TextElement( ", Date: " ) );
    header.addVariable( KDReports::TextDate );
    header.addInlineElement( KDReports::TextElement( ", Time: " ) );
    header.addVariable( KDReports::TextTime );

    KDReports::Header& evenPagesHeader = report.header( KDReports::EvenPages );
    evenPagesHeader.addElement( imageElement );
    evenPagesHeader.addInlineElement( KDReports::TextElement( "Even pages header: " ) );
    evenPagesHeader.addVariable( KDReports::PageNumber );
    evenPagesHeader.addInlineElement( KDReports::TextElement( " / " ) );
    evenPagesHeader.addVariable( KDReports::PageCount );

    KDReports::Footer& footer = report.footer();
    KDReports::TextElement companyAddressElement( QString::fromUtf8( "Klarälvdalens Datakonsult AB\nRysktorp\nSE-68392 Hagfors\nSweden" ) );
    footer.addElement( companyAddressElement, Qt::AlignRight );

    KDReports::TextElement titleElement;
    titleElement << "Price list example";
    titleElement.setPointSize( 18 );
    report.addElement( titleElement, Qt::AlignHCenter );

    report.addVerticalSpacing( 10 ); // 1 cm

    const QColor titleElementColor( 204, 204, 255 );

    // A text element with the title above a table
    // Note that the background color is not just behind the text (as setBackground() would do),
    // but behind the whole paragraph, up until the right margin of the page.
    KDReports::TextElement tableTitleElement( "Network Peripherals" );
    tableTitleElement.setBold( true );
    report.addElement( tableTitleElement, Qt::AlignLeft, titleElementColor );

    TableModel table1;
    table1.setDataHasVerticalHeaders( false );
    table1.loadFromCSV( ":/table1" );
    // Q_ASSERT( table1.headerData( 0, Qt::Vertical ).toString() == "10/100 Mbps switch" );
    //Q_ASSERT( table1.data( table1.index( 0, 0 ) ).toString() == "Product" );
    KDReports::AutoTableElement autoTableElement1( &table1 );
    autoTableElement1.setWidth( 100, KDReports::Percent );
    report.addElement( autoTableElement1 );

    report.addVerticalSpacing( 5 );

    // Notice how elements can be copied and modified
    // This way, we use the same font attributes for all title elements
    KDReports::TextElement tableTitleElement2 = tableTitleElement;
    tableTitleElement2.setText( "Printer Cartridges" );
    report.addElement( tableTitleElement2, Qt::AlignLeft, titleElementColor );

    TableModel table2;
    table2.setDataHasVerticalHeaders( false );
    table2.loadFromCSV( ":/table2" );
    KDReports::AutoTableElement autoTableElement2( &table2 );
    autoTableElement2.setWidth( 100, KDReports::Percent );
    report.addElement( autoTableElement2 );

    // and again, on the second page
    report.addPageBreak();
    report.addElement( tableTitleElement, Qt::AlignLeft, titleElementColor );
    report.addElement( autoTableElement1 );
    report.addVerticalSpacing( 5 );
    report.addElement( tableTitleElement2, Qt::AlignLeft, titleElementColor );
    report.addElement( autoTableElement2 );

    report.addVerticalSpacing( 5 );

    // ===========================================================================
    // Another kind of table, where the data comes from code and not from a model:
    // ===========================================================================
    KDReports::TableElement tableElement;
    tableElement.setHeaderRowCount( 2 );
    tableElement.setPadding( 3 );
    QColor headerColor( "#DADADA" );
    // Merged header in row 0
    KDReports::Cell& topHeader = tableElement.cell( 0, 0 );
    topHeader.setColumnSpan( 2 );
    topHeader.setBackground( headerColor );
    topHeader.addElement( KDReports::TextElement( "TableElement example" ), Qt::AlignHCenter );

    // Normal header in row 1
    KDReports::Cell& headerCell1 = tableElement.cell( 1, 0 );
    headerCell1.setBackground( headerColor );
    // This would look better if centered vertically. This feature is only available since
    // Qt-4.3 though (QTextCharFormat::AlignMiddle)
    QPixmap systemPixmap( ":/system.png" );
    headerCell1.addElement( KDReports::ImageElement( systemPixmap ) );
    headerCell1.addInlineElement( KDReports::TextElement( " Item" ) );
    KDReports::Cell& headerCell2 = tableElement.cell( 1, 1 );
    headerCell2.setBackground( headerColor );
    KDReports::TextElement expected( "Expected" );
    expected.setItalic( true );
    expected.setBackground( QColor("#999999") ); // note that this background only applies to this element
    headerCell2.addElement( expected );
    headerCell2.addInlineElement( KDReports::TextElement( " shipping time" ) );

    // Data in rows 2 and 3
    tableElement.cell( 2, 0 ).addElement( KDReports::TextElement( "Network Peripherals" ) );
    tableElement.cell( 2, 1 ).addElement( KDReports::TextElement( "4 days" ) );
    tableElement.cell( 3, 0 ).addElement( KDReports::TextElement( "Printer Cartridges" ) );
    tableElement.cell( 3, 1 ).addElement( KDReports::TextElement( "3 days" ) );

    report.addElement( tableElement );

    KDReports::PreviewDialog preview( &report );
    return preview.exec();
}
void ReportView::generate()
{
    // Check if there are rows in model. If so, generate report
    if(m_tableModel->rowCount() > 0)
    {
        // Create report container
        KDReports::Report report;

        // Generate table element using the table model
        KDReports::AutoTableElement tableElement(m_tableModel);
        // Show vertical header
        tableElement.setVerticalHeaderVisible(true);

        // Title text
        KDReports::TextElement title;
        title.setText("Transaction Report");
        // Show in bold format
        title.setBold(true);
        // Underline text
        title.setUnderline(true);
        // Set font size to 20
        title.setPointSize(20);
        // Add title to report
        report.addElement(title);

        // Insert vertical spacing for easier reading
        report.addVerticalSpacing(2);

        // Text to display report date
        KDReports::TextElement date;
        // Insert to date
        date << "Date: " << m_genData.fromDate.toString();

        // Check if report is not daily
        if(!m_genData.daily)
            // Add to date
            date << " - " << m_genData.toDate.toString();

        // Insert date element in to report
        report.addElement(date);

        // Insert 10 mm vertical spacing
        report.addVerticalSpacing(10);

        // Insert table element
        report.addElement(tableElement);

        // Insert a further 10 mm vertical spacing
        report.addVerticalSpacing(10);

        // Get report sums
        ReportTable::Sums sums = static_cast<ReportTable*>(m_tableModel)
                ->GetSums(m_genData);

        // Check validity of data
        if(sums.cost == -1)
        {
            // Data invalid, notify user
            QMessageBox::critical(this, "Failed to generate report.",
                            "Report data is invalid.",
                             QMessageBox::Ok);
            // Exit function
            return;
        }


        // Total revenue text
        KDReports::TextElement revenueTotal;
        // insert total revenue values
        revenueTotal << "Total revenue: "
                // convert to localized currency format
                << QLocale::system().toCurrencyString(sums.revenue);


        // total cost text
        KDReports::TextElement costTotal;
        costTotal << "Total cost: "
                // convert to localized currency format
                << QLocale::system().toCurrencyString(sums.cost);

        // total profit text
        KDReports::TextElement profitTotal;
        profitTotal << "Total profit: "
                // convert to localized currency format
                << QLocale::system().toCurrencyString(sums.profit);


        // Add revenue total to report
        report.addElement(revenueTotal);
        // Add cost total to report
        report.addElement(costTotal);
        // Add profit total to report
        report.addElement(profitTotal);

        // Create preview dialog using report.
        KDReports::PreviewDialog preview(&report);

        // Show preview dialog
        preview.exec();
    }
    else    // No data in table model
    {
        // Notify user of error
        QMessageBox::warning(this, "No report generated.",
               "Please generate a report before attempting to print it.",
                QMessageBox::Ok);
    }
}