You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1082 lines
35 KiB
1082 lines
35 KiB
/***************************************************************************
|
|
mreportengine.cpp - Kugar report engine
|
|
-------------------
|
|
begin : Sun Aug 15 1999
|
|
copyright : (C) 1999 by Mutiny Bay Software
|
|
email : info@mutinybaysoftware.com
|
|
copyright : (C) 2002 Alexander Dymo
|
|
email : cloudtemple@mksat.net
|
|
***************************************************************************/
|
|
|
|
#include <qfile.h>
|
|
#include <qprinter.h>
|
|
|
|
#include "mreportengine.h"
|
|
#include "mutil.h"
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <math.h>
|
|
|
|
namespace Kugar
|
|
{
|
|
|
|
/** Constructor */
|
|
MReportEngine::MReportEngine() : QObject()
|
|
{
|
|
// Set page params
|
|
m_pageCollection = 0;
|
|
m_needRegeneration = true;
|
|
m_refCount = 1;
|
|
pageSize = MReportEngine::Letter;
|
|
pageOrientation = MReportEngine::Portrait;
|
|
topMargin = 0;
|
|
bottomMargin = 0;
|
|
leftMargin = 0;
|
|
rightMargin = 0;
|
|
heightOfDetails = 0;
|
|
widthDelta = 1;
|
|
heightDelta = 1;
|
|
|
|
// Set cancel flag
|
|
cancelRender = false;
|
|
|
|
// Set the grand total list to AutoDelete
|
|
grandTotal.setAutoDelete( true );
|
|
// Set the details lists to AutoDelete
|
|
dHeaders.setAutoDelete( true );
|
|
details.setAutoDelete( true );
|
|
dFooters.setAutoDelete( true );
|
|
|
|
rHeader.setPrintFrequency( MReportSection::FirstPage );
|
|
pHeader.setPrintFrequency( MReportSection::EveryPage );
|
|
pFooter.setPrintFrequency( MReportSection::EveryPage );
|
|
rFooter.setPrintFrequency( MReportSection::LastPage );
|
|
|
|
// Set the default page metrics
|
|
QSize ps = getPageMetrics( pageSize, pageOrientation );
|
|
pageWidth = ps.width();
|
|
pageHeight = ps.height();
|
|
}
|
|
|
|
/** Copy constructor */
|
|
MReportEngine::MReportEngine( const MReportEngine& mReportEngine ) /*: QObject((QObject &) mReportEngine)*/
|
|
{
|
|
copy( &mReportEngine );
|
|
}
|
|
|
|
/** Assignment operator */
|
|
MReportEngine MReportEngine::operator=( const MReportEngine& mReportEngine )
|
|
{
|
|
if ( &mReportEngine == this )
|
|
return * this;
|
|
|
|
// Copy the derived class's data
|
|
copy( &mReportEngine );
|
|
|
|
// Copy the base class's data
|
|
//((QObject &) *this) = mReportEngine;
|
|
|
|
return *this;
|
|
}
|
|
|
|
/** Destructor */
|
|
MReportEngine::~MReportEngine()
|
|
{
|
|
// Clear the grand total data
|
|
grandTotal.clear();
|
|
kdDebug( 31000 ) << k_funcinfo << endl;
|
|
}
|
|
|
|
void MReportEngine::addRef()
|
|
{
|
|
m_refCount++;
|
|
}
|
|
|
|
void MReportEngine::removeRef()
|
|
{
|
|
m_refCount--;
|
|
if ( !m_refCount )
|
|
deleteLater();
|
|
}
|
|
|
|
/** Clears report formatting */
|
|
void MReportEngine::clearFormatting()
|
|
{
|
|
rHeader.clear();
|
|
pHeader.clear();
|
|
dHeaders.clear();
|
|
details.clear();
|
|
dFooters.clear();
|
|
pFooter.clear();
|
|
rFooter.clear();
|
|
}
|
|
|
|
|
|
//Set the report data from an existing QDomDocument
|
|
bool MReportEngine::setReportData( const QDomDocument &data )
|
|
{
|
|
rd = data.cloneNode( true ).toDocument();
|
|
initData();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Set the report's data from an inline string. Return true if it was valid
|
|
// data.
|
|
|
|
bool MReportEngine::setReportData( const QString &data )
|
|
{
|
|
|
|
if ( !rd.setContent( data ) )
|
|
{
|
|
kdDebug() << "Unable to parse report data" << endl;
|
|
return false;
|
|
}
|
|
initData();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Set the report's data from an i/o device. Return true if it was valid data.
|
|
|
|
bool MReportEngine::setReportData( QIODevice *dev )
|
|
{
|
|
if ( !rd.setContent( dev ) )
|
|
{
|
|
kdDebug() << "Unable to parse report data" << endl;
|
|
return false;
|
|
}
|
|
initData();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Initialise after reading a report's data.
|
|
|
|
void MReportEngine::initData()
|
|
{
|
|
m_needRegeneration = true;
|
|
// Get the record set (we assume there is only one).
|
|
|
|
for ( QDomNode n = rd.firstChild(); !n.isNull(); n = n.nextSibling() )
|
|
if ( n.nodeName() == "KugarData" )
|
|
{
|
|
// Get the records.
|
|
|
|
records = n.childNodes();
|
|
|
|
// See if there is a prefered template given.
|
|
|
|
QDomNamedNodeMap attr = n.attributes();
|
|
QDomNode tempattr = attr.namedItem( "Template" );
|
|
QString tempname = tempattr.nodeValue();
|
|
|
|
if ( !tempname.isNull() )
|
|
emit preferedTemplate( tempname );
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Set the report's template from an inline string. Return true if it was a
|
|
// valid template.
|
|
|
|
bool MReportEngine::setReportTemplate( const QString &tpl )
|
|
{
|
|
clearFormatting();
|
|
|
|
if ( !rt.setContent( tpl ) )
|
|
{
|
|
kdDebug() << "Unable to parse report template" << endl;
|
|
return false;
|
|
}
|
|
|
|
initTemplate();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Set the report's template from an i/o device. Return true if it was a valid
|
|
// template.
|
|
|
|
bool MReportEngine::setReportTemplate( QIODevice *dev )
|
|
{
|
|
clearFormatting();
|
|
|
|
if ( !rt.setContent( dev ) )
|
|
{
|
|
kdDebug() << "Unable to parse report template" << endl;
|
|
return false;
|
|
}
|
|
|
|
initTemplate();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/** Cancels rendering of a report */
|
|
void MReportEngine::slotCancelRendering()
|
|
{
|
|
cancelRender = true;
|
|
}
|
|
|
|
/** Finds the detail header object, which is apropriate for the given level */
|
|
MReportSection *MReportEngine::findDetailHeader( int level )
|
|
{
|
|
MReportSection * sec;
|
|
for ( sec = dHeaders.first(); sec; sec = dHeaders.next() )
|
|
{
|
|
if ( sec->getLevel() == level )
|
|
return sec;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/** Finds the detail object, which is apropriate for the given level */
|
|
MReportDetail *MReportEngine::findDetail( int level )
|
|
{
|
|
MReportDetail * sec;
|
|
for ( sec = details.first(); sec; sec = details.next() )
|
|
{
|
|
if ( sec->getLevel() == level )
|
|
return sec;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/** Finds the detail footer object, which is apropriate for the given level */
|
|
MReportSection *MReportEngine::findDetailFooter( int level )
|
|
{
|
|
MReportSection * sec;
|
|
for ( sec = dFooters.first(); sec; sec = dFooters.next() )
|
|
{
|
|
if ( sec->getLevel() == level )
|
|
return sec;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/** Renders the report as a page collection - the caller
|
|
* is responsible for de-allocating the returned
|
|
* collection
|
|
*/
|
|
MPageCollection* MReportEngine::renderReport()
|
|
{
|
|
if ( !m_needRegeneration )
|
|
return m_pageCollection;
|
|
if ( m_pageCollection )
|
|
{
|
|
m_pageCollection->deleteLater();
|
|
m_pageCollection = 0;
|
|
}
|
|
|
|
unsigned int j;
|
|
unsigned int i;
|
|
|
|
// Set cancel flag
|
|
cancelRender = false;
|
|
|
|
// Create the page collection
|
|
MPageCollection* pages = new MPageCollection( this );
|
|
|
|
// Initialize the basic page data
|
|
currHeight = pageHeight - ( topMargin + bottomMargin + pFooter.getHeight() );
|
|
currPage = 0;
|
|
currDate = QDate::currentDate();
|
|
|
|
// Initialise global report variables
|
|
unsigned int rowCount = records.length();
|
|
for ( j = 0; j < rowCount; j++ )
|
|
{
|
|
QDomNode record = records.item( j );
|
|
if ( ( record.nodeType() == QDomNode::ElementNode )
|
|
&& ( record.nodeName() == "Var" ) )
|
|
{
|
|
// Process the variable ...
|
|
QDomNamedNodeMap fields = record.attributes();
|
|
for ( int k = 0; k < fields.count(); ++k )
|
|
{
|
|
rHeader.setFieldData( fields.item( k ).nodeName(), fields.item( k ).nodeValue() );
|
|
rFooter.setFieldData( fields.item( k ).nodeName(), fields.item( k ).nodeValue() );
|
|
pHeader.setFieldData( fields.item( k ).nodeName(), fields.item( k ).nodeValue() );
|
|
pFooter.setFieldData( fields.item( k ).nodeName(), fields.item( k ).nodeValue() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize the grand total array
|
|
grandTotal.clear();
|
|
for ( int i = 0; i < rFooter.getCalcFieldCount(); i++ )
|
|
grandTotal.append( new QMemArray<double> );
|
|
|
|
// Create the first page
|
|
startPage( pages );
|
|
|
|
// Draw the detail section by looping through all the records
|
|
int chkRow = 0;
|
|
int curDetailLevel = 0;
|
|
int prevDetailLevel = -1;
|
|
int curDetailHeader = -1;
|
|
int curDetailFooter = -1;
|
|
|
|
for ( j = 0; j < rowCount; j++ )
|
|
{
|
|
QString detailValue;
|
|
QDomNode record = records.item( j );
|
|
|
|
if ( ( record.nodeType() == QDomNode::ElementNode )
|
|
&& ( record.nodeName() == "Row" ) )
|
|
{
|
|
// Update status event
|
|
if ( ( chkRow = ( j / 2 ) % 20 ) == 0 )
|
|
emit signalRenderStatus( j / 2 );
|
|
|
|
// Check for cancel action
|
|
if ( cancelRender )
|
|
{
|
|
p.end();
|
|
delete pages;
|
|
return 0;
|
|
}
|
|
|
|
// Process the record ...
|
|
QDomNamedNodeMap fields = record.attributes();
|
|
|
|
// Find the detail object to process with rendering
|
|
detailValue = fields.namedItem( "level" ).nodeValue();
|
|
curDetailLevel = detailValue.toInt();
|
|
|
|
// Reset the header/footer detail levels?
|
|
curDetailHeader = curDetailLevel > curDetailHeader ? -1 : curDetailHeader;
|
|
curDetailFooter = curDetailLevel > curDetailFooter ? -1 : curDetailFooter;
|
|
|
|
// Draw detail footer if appropriate
|
|
if ( curDetailLevel <= prevDetailLevel )
|
|
{
|
|
// Draw footer for previous detail levels
|
|
// from prevDetailLevel up to curDetailLevel
|
|
// Draw footer for current detail level
|
|
for ( int i = prevDetailLevel; i >= curDetailLevel; i-- )
|
|
{
|
|
MReportSection *footer = findDetailFooter( i );
|
|
if ( footer )
|
|
{
|
|
footer->setPageNumber( currPage );
|
|
footer->setReportDate( currDate );
|
|
footer->setCalcFieldData( &grandTotal );
|
|
if ( ( currY + footer->getHeight() ) > currHeight )
|
|
{
|
|
newPage( pages );
|
|
}
|
|
footer->draw( &p, leftMargin, currY );
|
|
currY += footer->getHeight();
|
|
}
|
|
}
|
|
}
|
|
|
|
MReportDetail *detail = findDetail( detailValue.toInt() );
|
|
detail->setPageNumber( currPage );
|
|
detail->setReportDate( currDate );
|
|
|
|
int headerHeight = 0;
|
|
MReportSection * header = findDetailHeader( curDetailLevel );
|
|
if ( header && curDetailHeader != curDetailLevel )
|
|
headerHeight = header->getHeight();
|
|
|
|
bool repeating = ( currY + detail->getHeight() + headerHeight ) > currHeight ||
|
|
( detail->getRepeat() && currY + heightOfDetails > currHeight );
|
|
if ( repeating )
|
|
{
|
|
newPage( pages );
|
|
|
|
MReportDetail *sec;
|
|
for ( sec = details.first(); sec; sec = details.next() )
|
|
{
|
|
if ( sec->getLevel() != curDetailLevel && sec->getRepeat() )
|
|
{
|
|
sec->draw( &p, leftMargin, currY );
|
|
currY += sec->getHeight();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw detail header for level curDetailLevel
|
|
// if it hasn't already been drawn
|
|
if ( curDetailHeader != curDetailLevel || repeating )
|
|
{
|
|
MReportSection * header = findDetailHeader( curDetailLevel );
|
|
if ( header )
|
|
{
|
|
header->setPageNumber( currPage );
|
|
header->setReportDate( currDate );
|
|
if ( ( currY + header->getHeight() ) > currHeight )
|
|
{
|
|
newPage( pages );
|
|
}
|
|
header->draw( &p, leftMargin, currY );
|
|
currY += header->getHeight();
|
|
curDetailHeader = curDetailLevel;
|
|
}
|
|
}
|
|
|
|
unsigned int fieldCount = detail->getFieldCount();
|
|
for ( i = 0; i < fieldCount; i++ )
|
|
{
|
|
// Get the field value
|
|
detailValue = fields.namedItem( detail->getFieldName( i ) ).nodeValue();
|
|
// Set the field
|
|
detail->setFieldData( i, detailValue );
|
|
// Set the grand total data
|
|
int calcIdx = rFooter.getCalcFieldIndex( detail->getFieldName( i ) );
|
|
if ( calcIdx != -1 )
|
|
{
|
|
int vsize = grandTotal.at( calcIdx ) ->size();
|
|
grandTotal.at( calcIdx ) ->resize( vsize + 1 );
|
|
grandTotal.at( calcIdx ) ->at( vsize ) = detailValue.toDouble();
|
|
}
|
|
}
|
|
|
|
detail->draw( &p, leftMargin, currY );
|
|
currY += detail->getHeight();
|
|
prevDetailLevel = curDetailLevel;
|
|
}
|
|
}
|
|
|
|
// Draw detail footers that were not drawn before
|
|
// for details from curDetailLevel up to prevDetailLevel
|
|
for ( int i = prevDetailLevel; i >= 0; i-- )
|
|
{
|
|
MReportSection *footer = findDetailFooter( i );
|
|
if ( footer )
|
|
{
|
|
footer->setPageNumber( currPage );
|
|
footer->setReportDate( currDate );
|
|
footer->setCalcFieldData( &grandTotal );
|
|
if ( ( currY + footer->getHeight() ) > currHeight )
|
|
{
|
|
newPage( pages );
|
|
}
|
|
|
|
footer->draw( &p, leftMargin, currY );
|
|
currY += footer->getHeight();
|
|
}
|
|
}
|
|
|
|
// Finish the last page of the report
|
|
endPage( pages );
|
|
|
|
// Destroy the page painter
|
|
p.end();
|
|
|
|
// Set the page collection attributes
|
|
pages->setPageDimensions( QSize( pageWidth, pageHeight ) );
|
|
pages->setPageSize( pageSize );
|
|
pages->setPageOrientation( pageOrientation );
|
|
|
|
// Send final status
|
|
emit signalRenderStatus( rowCount / 2 );
|
|
m_needRegeneration = false;
|
|
m_pageCollection = pages;
|
|
return pages;
|
|
}
|
|
|
|
/** Starts a new page of the report */
|
|
void MReportEngine::startPage( MPageCollection* pages )
|
|
{
|
|
// Set the current y pos
|
|
currY = topMargin;
|
|
|
|
// Create a new page
|
|
pages->appendPage();
|
|
// Increment the page count
|
|
currPage++;
|
|
|
|
// Set the page painter to the current page
|
|
p.begin( pages->getCurrentPage() );
|
|
|
|
// Draw the report header
|
|
drawReportHeader( pages );
|
|
// Draw the page header
|
|
drawPageHeader( pages );
|
|
}
|
|
|
|
/** Finishes the current page of the report */
|
|
void MReportEngine::endPage( MPageCollection* pages )
|
|
{
|
|
// Draw the report footer
|
|
drawReportFooter( pages );
|
|
// Draw the page footer
|
|
drawPageFooter( pages );
|
|
}
|
|
|
|
/** Finishes the current page and adds a new page */
|
|
void MReportEngine::newPage( MPageCollection* pages )
|
|
{
|
|
// Draw the page footer
|
|
drawPageFooter( pages );
|
|
|
|
// Stop the painter
|
|
p.end();
|
|
|
|
// Start a new page
|
|
startPage( pages );
|
|
}
|
|
|
|
/** Draws the report header object to the current page */
|
|
void MReportEngine::drawReportHeader( MPageCollection* pages )
|
|
{
|
|
if ( rHeader.getHeight() == 0 )
|
|
return ;
|
|
|
|
if ( ( rHeader.printFrequency() == MReportSection::FirstPage && currPage == 1 )
|
|
|| ( rHeader.printFrequency() == MReportSection::EveryPage ) )
|
|
{
|
|
|
|
rHeader.setPageNumber( currPage );
|
|
rHeader.setReportDate( currDate );
|
|
rHeader.draw( &p, leftMargin, currY );
|
|
currY += rHeader.getHeight();
|
|
}
|
|
}
|
|
|
|
/** Draws the page header to the current page */
|
|
void MReportEngine::drawPageHeader( MPageCollection* pages )
|
|
{
|
|
if ( pHeader.getHeight() == 0 )
|
|
return ;
|
|
|
|
if ( ( currY + pHeader.getHeight() ) > currHeight )
|
|
newPage( pages );
|
|
|
|
if ( ( pHeader.printFrequency() == MReportSection::FirstPage && currPage == 1 )
|
|
|| ( pHeader.printFrequency() == MReportSection::EveryPage ) )
|
|
{
|
|
|
|
pHeader.setPageNumber( currPage );
|
|
pHeader.setReportDate( currDate );
|
|
pHeader.draw( &p, leftMargin, currY );
|
|
currY += pHeader.getHeight();
|
|
}
|
|
}
|
|
|
|
/** Draws the page footer to the current page */
|
|
void MReportEngine::drawPageFooter( MPageCollection* pages )
|
|
{
|
|
if ( pFooter.getHeight() == 0 )
|
|
return ;
|
|
|
|
if ( ( pFooter.printFrequency() == MReportSection::FirstPage && currPage == 1 )
|
|
|| ( pFooter.printFrequency() == MReportSection::EveryPage ) )
|
|
{
|
|
|
|
pFooter.setPageNumber( currPage );
|
|
pFooter.setReportDate( currDate );
|
|
pFooter.draw( &p, leftMargin, ( pageHeight - bottomMargin ) - pFooter.getHeight() );
|
|
currY += pFooter.getHeight();
|
|
}
|
|
}
|
|
|
|
/** Draws the report footer to the current page */
|
|
void MReportEngine::drawReportFooter( MPageCollection* pages )
|
|
{
|
|
if ( rFooter.getHeight() == 0 )
|
|
return ;
|
|
|
|
if ( ( currY + rFooter.getHeight() ) > currHeight )
|
|
newPage( pages );
|
|
|
|
if ( ( rFooter.printFrequency() == MReportSection::EveryPage )
|
|
|| ( rFooter.printFrequency() == MReportSection::LastPage ) )
|
|
{
|
|
|
|
rFooter.setCalcFieldData( &grandTotal );
|
|
|
|
rFooter.setPageNumber( currPage );
|
|
rFooter.setReportDate( currDate );
|
|
rFooter.draw( &p, leftMargin, currY );
|
|
currY += rFooter.getHeight();
|
|
}
|
|
}
|
|
|
|
/** Gets the metrics for the selected page size & orientation */
|
|
QSize MReportEngine::getPageMetrics( int size, int orientation )
|
|
{
|
|
|
|
QPrinter * printer;
|
|
QSize ps;
|
|
|
|
// Set the page size
|
|
printer = new QPrinter();
|
|
printer->setFullPage( true );
|
|
printer->setPageSize( ( QPrinter::PageSize ) size );
|
|
printer->setOrientation( ( QPrinter::Orientation ) orientation );
|
|
|
|
// Get the page metrics
|
|
QPaintDeviceMetrics pdm( printer );
|
|
|
|
// Display the first page of the report
|
|
ps.setWidth( pdm.width() );
|
|
ps.setHeight( pdm.height() );
|
|
|
|
delete printer;
|
|
|
|
return ps;
|
|
}
|
|
|
|
|
|
/**
|
|
This recalculates report dimensions to 96 dpi, standard on Windows
|
|
platform.
|
|
|
|
FIXME: TODO: get the proper screen resolution and not hardcode 96dpi
|
|
FIXME: TODO: make this function work on X11 too
|
|
*/
|
|
void MReportEngine::recalcDimensions()
|
|
{
|
|
QDomNode report;
|
|
QDomNode child;
|
|
for ( report = rt.firstChild(); !report.isNull(); report = report.nextSibling() )
|
|
if ( report.nodeName() == "KugarTemplate" )
|
|
break;
|
|
|
|
QDomNamedNodeMap rattributes = report.attributes();
|
|
recalcAttribute( "BottomMargin", rattributes );
|
|
recalcAttribute( "TopMargin", rattributes );
|
|
recalcAttribute( "LeftMargin", rattributes );
|
|
recalcAttribute( "RightMargin", rattributes );
|
|
|
|
QDomNodeList children = report.childNodes();
|
|
int childCount = children.length();
|
|
|
|
for ( int j = 0; j < childCount; j++ )
|
|
{
|
|
child = children.item( j );
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
|
|
QDomNodeList children2 = child.childNodes();
|
|
int childCount2 = children2.length();
|
|
recalcAttribute( "Height", attributes );
|
|
|
|
for ( int k = 0; k < childCount2; k++ )
|
|
{
|
|
QDomNode child2 = children2.item( k );
|
|
QDomNamedNodeMap attributes = child2.attributes();
|
|
recalcAttribute( "X", attributes );
|
|
recalcAttribute( "Y", attributes );
|
|
recalcAttribute( "Width", attributes );
|
|
recalcAttribute( "Height", attributes );
|
|
recalcAttribute( "X1", attributes );
|
|
recalcAttribute( "X2", attributes );
|
|
recalcAttribute( "Y1", attributes );
|
|
recalcAttribute( "Y2", attributes );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void MReportEngine::recalcAttribute( const QString& name, QDomNamedNodeMap attributes )
|
|
{
|
|
if ( !attributes.namedItem( name ).isNull() )
|
|
{
|
|
attributes.namedItem( name ).setNodeValue( QString( "%1" ).arg( attributes.namedItem( name ).nodeValue().toInt() * 93 / 81 ) );
|
|
}
|
|
}
|
|
|
|
/** Walks the document tree, setting the report layout */
|
|
void MReportEngine::initTemplate()
|
|
{
|
|
heightOfDetails = 0;
|
|
|
|
#ifdef Q_WS_WIN
|
|
|
|
recalcDimensions();
|
|
#endif
|
|
|
|
QDomNode report;
|
|
QDomNode child;
|
|
|
|
m_needRegeneration = true;
|
|
// Get the report - assume there is only one.
|
|
|
|
for ( report = rt.firstChild(); !report.isNull(); report = report.nextSibling() )
|
|
if ( report.nodeName() == "KugarTemplate" )
|
|
break;
|
|
|
|
setReportAttributes( &report );
|
|
|
|
// Get all the child report elements
|
|
QDomNodeList children = report.childNodes();
|
|
int childCount = children.length();
|
|
|
|
for ( int j = 0; j < childCount; j++ )
|
|
{
|
|
child = children.item( j );
|
|
|
|
if ( child.nodeType() == QDomNode::ElementNode )
|
|
{
|
|
// Report Header
|
|
if ( child.nodeName() == "ReportHeader" )
|
|
setSectionAttributes( &rHeader, &child );
|
|
else if ( child.nodeName() == "PageHeader" )
|
|
setSectionAttributes( &pHeader, &child );
|
|
else if ( child.nodeName() == "DetailHeader" )
|
|
{
|
|
MReportSection * dHeader = new MReportSection;
|
|
dHeaders.append( dHeader );
|
|
setDetMiscAttributes( dHeader, &child );
|
|
}
|
|
else if ( child.nodeName() == "Detail" )
|
|
setDetailAttributes( &child );
|
|
else if ( child.nodeName() == "DetailFooter" )
|
|
{
|
|
MReportSection * dFooter = new MReportSection;
|
|
setDetMiscAttributes( dFooter, &child );
|
|
dFooters.append( dFooter );
|
|
}
|
|
else if ( child.nodeName() == "PageFooter" )
|
|
setSectionAttributes( &pFooter, &child );
|
|
else if ( child.nodeName() == "ReportFooter" )
|
|
setSectionAttributes( &rFooter, &child );
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Sets the main layout attributes for the report */
|
|
void MReportEngine::setReportAttributes( QDomNode* report )
|
|
{
|
|
// Get the attributes for the report
|
|
QDomNamedNodeMap attributes = report->attributes();
|
|
|
|
pageSize = attributes.namedItem( "PageSize" ).nodeValue().toInt();
|
|
pageOrientation = attributes.namedItem( "PageOrientation" ).nodeValue().toInt();
|
|
int templateWidth = attributes.namedItem( "PageWidth" ).nodeValue().toInt();
|
|
int templateheight = attributes.namedItem( "PageHeight" ).nodeValue().toInt();
|
|
|
|
QSize ps = getPageMetrics( pageSize, pageOrientation );
|
|
pageWidth = ps.width();
|
|
pageHeight = ps.height();
|
|
|
|
widthDelta = ( float ) pageWidth / templateWidth;
|
|
heightDelta = ( float ) pageHeight / templateheight;
|
|
|
|
kdDebug( 30001 ) << "pagewidth: " << pageWidth
|
|
<< " pageheight: " << pageHeight << "\n"
|
|
<< "templateWidth: " << templateWidth
|
|
<< " templateheight: " << templateheight << "\n"
|
|
<< "widthDelta: " << widthDelta
|
|
<< " heightDelta: " << heightDelta
|
|
<< endl;
|
|
|
|
topMargin = scaleDeltaHeight( attributes.namedItem( "TopMargin" ).nodeValue().toInt() );
|
|
bottomMargin = scaleDeltaHeight( attributes.namedItem( "BottomMargin" ).nodeValue().toInt() );
|
|
leftMargin = scaleDeltaWidth( attributes.namedItem( "LeftMargin" ).nodeValue().toInt() );
|
|
rightMargin = scaleDeltaWidth( attributes.namedItem( "RightMargin" ).nodeValue().toInt() );
|
|
}
|
|
|
|
int MReportEngine::scaleDeltaWidth( int width ) const
|
|
{
|
|
float f = width * widthDelta;
|
|
return f > 1 ? int( f + 0.5) : ceil( f );
|
|
}
|
|
|
|
int MReportEngine::scaleDeltaHeight( int height ) const
|
|
{
|
|
float f = height * heightDelta;
|
|
return f > 1 ? int( f + 0.5 ) : ceil( f );
|
|
}
|
|
|
|
/** Sets the layout attributes for the given report section */
|
|
void MReportEngine::setSectionAttributes( MReportSection* section, QDomNode* report )
|
|
{
|
|
// Get the attributes for the section
|
|
QDomNamedNodeMap attributes = report->attributes();
|
|
|
|
// Get the section attributes
|
|
section->setHeight( scaleDeltaHeight( attributes.namedItem( "Height" ).nodeValue().toInt() ) );
|
|
section->setPrintFrequency( attributes.namedItem( "PrintFrequency" ).nodeValue().toInt() );
|
|
|
|
// Process the sections labels
|
|
QDomNodeList children = report->childNodes();
|
|
int childCount = children.length();
|
|
|
|
// For each label, extract the attr list and add the new label
|
|
// to the sections's label collection
|
|
for ( int j = 0; j < childCount; j++ )
|
|
{
|
|
QDomNode child = children.item( j );
|
|
if ( child.nodeType() == QDomNode::ElementNode )
|
|
{
|
|
if ( child.nodeName() == "Line" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MLineObject* line = new MLineObject();
|
|
setLineAttributes( line, &attributes );
|
|
section->addLine( line );
|
|
}
|
|
else if ( child.nodeName() == "Label" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MLabelObject* label = new MLabelObject();
|
|
setLabelAttributes( label, &attributes );
|
|
section->addLabel( label );
|
|
}
|
|
else if ( child.nodeName() == "Special" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MSpecialObject* field = new MSpecialObject();
|
|
setSpecialAttributes( field, &attributes );
|
|
section->addSpecialField( field );
|
|
}
|
|
else if ( child.nodeName() == "CalculatedField" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MCalcObject* field = new MCalcObject();
|
|
setCalculatedFieldAttributes( field, &attributes );
|
|
section->addCalculatedField( field );
|
|
}
|
|
else if ( child.nodeName() == "Field" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MFieldObject* field = new MFieldObject();
|
|
setFieldAttributes( field, &attributes );
|
|
section->addField( field );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Sets the layout attributes for the detail headers and footers */
|
|
void MReportEngine::setDetMiscAttributes( MReportSection* section, QDomNode* report )
|
|
{
|
|
// Get the attributes for the section
|
|
QDomNamedNodeMap attributes = report->attributes();
|
|
|
|
// Get the section attributes
|
|
section->setLevel( attributes.namedItem( "Level" ).nodeValue().toInt() );
|
|
|
|
// Set other section attributes
|
|
setSectionAttributes( section, report );
|
|
}
|
|
|
|
|
|
/** Sets the layout attributes for the detail section */
|
|
void MReportEngine::setDetailAttributes( QDomNode* report )
|
|
{
|
|
// Get the attributes for the detail section
|
|
QDomNamedNodeMap attributes = report->attributes();
|
|
|
|
// Get the report detail attributes
|
|
MReportDetail *detail = new MReportDetail;
|
|
int height = scaleDeltaHeight( attributes.namedItem( "Height" ).nodeValue().toInt() );
|
|
heightOfDetails += height;
|
|
detail->setHeight( height );
|
|
detail->setLevel( attributes.namedItem( "Level" ).nodeValue().toInt() );
|
|
detail->setRepeat( attributes.namedItem( "Repeat" ).nodeValue() == "true" );
|
|
|
|
// Process the report detail labels
|
|
QDomNodeList children = report->childNodes();
|
|
int childCount = children.length();
|
|
|
|
for ( int j = 0; j < childCount; j++ )
|
|
{
|
|
QDomNode child = children.item( j );
|
|
if ( child.nodeType() == QDomNode::ElementNode )
|
|
{
|
|
if ( child.nodeName() == "Line" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MLineObject* line = new MLineObject();
|
|
setLineAttributes( line, &attributes );
|
|
detail->addLine( line );
|
|
}
|
|
else if ( child.nodeName() == "Label" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MLabelObject* label = new MLabelObject();
|
|
setLabelAttributes( label, &attributes );
|
|
detail->addLabel( label );
|
|
}
|
|
else if ( child.nodeName() == "Special" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MSpecialObject* field = new MSpecialObject();
|
|
setSpecialAttributes( field, &attributes );
|
|
detail->addSpecialField( field );
|
|
}
|
|
else if ( child.nodeName() == "Field" )
|
|
{
|
|
QDomNamedNodeMap attributes = child.attributes();
|
|
MFieldObject* field = new MFieldObject();
|
|
setFieldAttributes( field, &attributes );
|
|
detail->addField( field );
|
|
}
|
|
}
|
|
}
|
|
// Append a newly created detail to the list
|
|
details.append( detail );
|
|
}
|
|
|
|
/** Sets a line's layout attributes */
|
|
void MReportEngine::setLineAttributes( MLineObject* line, QDomNamedNodeMap* attr )
|
|
{
|
|
line->setLine( scaleDeltaWidth( attr->namedItem( "X1" ).nodeValue().toInt() ),
|
|
scaleDeltaHeight( attr->namedItem( "Y1" ).nodeValue().toInt() ),
|
|
scaleDeltaWidth( attr->namedItem( "X2" ).nodeValue().toInt() ),
|
|
scaleDeltaHeight( attr->namedItem( "Y2" ).nodeValue().toInt() ) );
|
|
|
|
QString tmp = attr->namedItem( "Color" ).nodeValue();
|
|
|
|
line->setColor( tmp.left( tmp.find( "," ) ).toInt(),
|
|
tmp.mid( tmp.find( "," ) + 1, ( tmp.findRev( "," ) - tmp.find( "," ) ) - 1 ).toInt(),
|
|
tmp.right( tmp.length() - tmp.findRev( "," ) - 1 ).toInt() );
|
|
|
|
line->setWidth( attr->namedItem( "Width" ).nodeValue().toInt() );
|
|
line->setStyle( attr->namedItem( "Style" ).nodeValue().toInt() );
|
|
}
|
|
|
|
/** Sets a label's layout attributes */
|
|
void MReportEngine::setLabelAttributes( MLabelObject* label, QDomNamedNodeMap* attr )
|
|
{
|
|
QString tmp;
|
|
|
|
label->setText( attr->namedItem( "Text" ).nodeValue() );
|
|
label->setGeometry( scaleDeltaWidth( attr->namedItem( "X" ).nodeValue().toInt() ),
|
|
scaleDeltaHeight( attr->namedItem( "Y" ).nodeValue().toInt() ),
|
|
scaleDeltaWidth( attr->namedItem( "Width" ).nodeValue().toInt() ),
|
|
scaleDeltaHeight( attr->namedItem( "Height" ).nodeValue().toInt() ) );
|
|
|
|
tmp = attr->namedItem( "BackgroundColor" ).nodeValue();
|
|
label->setBackgroundColor( tmp.left( tmp.find( "," ) ).toInt(),
|
|
tmp.mid( tmp.find( "," ) + 1, ( tmp.findRev( "," ) - tmp.find( "," ) ) - 1 ).toInt(),
|
|
tmp.right( tmp.length() - tmp.findRev( "," ) - 1 ).toInt() );
|
|
|
|
tmp = attr->namedItem( "ForegroundColor" ).nodeValue();
|
|
label->setForegroundColor( tmp.left( tmp.find( "," ) ).toInt(),
|
|
tmp.mid( tmp.find( "," ) + 1, ( tmp.findRev( "," ) - tmp.find( "," ) ) - 1 ).toInt(),
|
|
tmp.right( tmp.length() - tmp.findRev( "," ) - 1 ).toInt() );
|
|
|
|
tmp = attr->namedItem( "BorderColor" ).nodeValue();
|
|
label->setBorderColor( tmp.left( tmp.find( "," ) ).toInt(),
|
|
tmp.mid( tmp.find( "," ) + 1, ( tmp.findRev( "," ) - tmp.find( "," ) ) - 1 ).toInt(),
|
|
tmp.right( tmp.length() - tmp.findRev( "," ) - 1 ).toInt() );
|
|
|
|
label->setBorderWidth( attr->namedItem( "BorderWidth" ).nodeValue().toInt() );
|
|
label->setBorderStyle( attr->namedItem( "BorderStyle" ).nodeValue().toInt() );
|
|
if ( !attr->namedItem( "DrawBottom" ).isNull() )
|
|
label->setDrawBottom( attr->namedItem( "DrawBottom" ).nodeValue() == "true" );
|
|
if ( !attr->namedItem( "DrawTop" ).isNull() )
|
|
label->setDrawTop( attr->namedItem( "DrawTop" ).nodeValue() == "true" );
|
|
if ( !attr->namedItem( "DrawLeft" ).isNull() )
|
|
label->setDrawLeft( attr->namedItem( "DrawLeft" ).nodeValue() == "true" );
|
|
if ( !attr->namedItem( "DrawRight" ).isNull() )
|
|
label->setDrawRight( attr->namedItem( "DrawRight" ).nodeValue() == "true" );
|
|
label->setFont( attr->namedItem( "FontFamily" ).nodeValue(),
|
|
attr->namedItem( "FontSize" ).nodeValue().toInt(),
|
|
attr->namedItem( "FontWeight" ).nodeValue().toInt(),
|
|
( attr->namedItem( "FontItalic" ).nodeValue().toInt() == 0 ? false : true ) );
|
|
label->setHorizontalAlignment( attr->namedItem( "HAlignment" ).nodeValue().toInt() );
|
|
label->setVerticalAlignment( attr->namedItem( "VAlignment" ).nodeValue().toInt() );
|
|
label->setWordWrap( attr->namedItem( "WordWrap" ).nodeValue().toInt() == 0 ? false : true );
|
|
}
|
|
|
|
/** Sets a special field's layout attributes */
|
|
void MReportEngine::setSpecialAttributes( MSpecialObject* field, QDomNamedNodeMap* attr )
|
|
{
|
|
field->setType( attr->namedItem( "Type" ).nodeValue().toInt() );
|
|
field->setDateFormat( attr->namedItem( "DateFormat" ).nodeValue().toInt() );
|
|
|
|
setLabelAttributes( ( MLabelObject * ) field, attr );
|
|
}
|
|
|
|
/** Sets a field's layout attributes */
|
|
void MReportEngine::setFieldAttributes( MFieldObject* field, QDomNamedNodeMap* attr )
|
|
{
|
|
field->setFieldName( attr->namedItem( "Field" ).nodeValue() );
|
|
field->setDataType( attr->namedItem( "DataType" ).nodeValue().toInt() );
|
|
field->setDateFormat( attr->namedItem( "DateFormat" ).nodeValue().toInt() );
|
|
field->setPrecision( attr->namedItem( "Precision" ).nodeValue().toInt() );
|
|
field->setCurrency( attr->namedItem( "Currency" ).nodeValue().toInt() );
|
|
field->setCommaSeparator( attr->namedItem( "CommaSeparator" ).nodeValue().toInt() );
|
|
field->setInputMask( attr->namedItem( "InputMask" ).nodeValue() );
|
|
|
|
QString tmp = attr->namedItem( "NegValueColor" ).nodeValue();
|
|
|
|
field->setNegValueColor( tmp.left( tmp.find( "," ) ).toInt(),
|
|
tmp.mid( tmp.find( "," ) + 1, ( tmp.findRev( "," ) - tmp.find( "," ) ) - 1 ).toInt(),
|
|
tmp.right( tmp.length() - tmp.findRev( "," ) - 1 ).toInt() );
|
|
|
|
setLabelAttributes( ( MLabelObject * ) field, attr );
|
|
}
|
|
|
|
/** Sets a calculated field's layout attributes */
|
|
void MReportEngine::setCalculatedFieldAttributes( MCalcObject* field, QDomNamedNodeMap* attr )
|
|
{
|
|
field->setCalculationType( attr->namedItem( "CalculationType" ).nodeValue().toInt() );
|
|
setFieldAttributes( ( MFieldObject * ) field, attr );
|
|
}
|
|
|
|
/** Copies member data from one object to another.
|
|
Used by the copy constructor and assignment operator */
|
|
void MReportEngine::copy( const MReportEngine* mReportEngine )
|
|
{
|
|
// Copy document data
|
|
m_refCount = 1;
|
|
rd = mReportEngine->rd;
|
|
rt = mReportEngine->rt;
|
|
|
|
// Copy page metrics
|
|
pageSize = mReportEngine->pageSize;
|
|
pageOrientation = mReportEngine->pageOrientation;
|
|
topMargin = mReportEngine->topMargin;
|
|
bottomMargin = mReportEngine->bottomMargin;
|
|
leftMargin = mReportEngine->leftMargin;
|
|
rightMargin = mReportEngine->rightMargin;
|
|
pageWidth = mReportEngine->pageWidth;
|
|
pageHeight = mReportEngine->pageHeight;
|
|
heightOfDetails = mReportEngine->heightOfDetails;
|
|
|
|
// Copy the report header
|
|
rHeader = mReportEngine->rHeader;
|
|
// Copy the page header
|
|
pHeader = mReportEngine->pHeader;
|
|
// Copy the detail sections
|
|
MReportDetail *detail;
|
|
QPtrList<MReportDetail> temp = mReportEngine->details;
|
|
temp.setAutoDelete( false );
|
|
for ( detail = temp.first(); detail; detail = temp.next() )
|
|
{
|
|
MReportDetail * new_detail = new MReportDetail;
|
|
*new_detail = *detail;
|
|
details.append( new_detail );
|
|
}
|
|
// Copy the page footer
|
|
pFooter = mReportEngine->pFooter;
|
|
// Copy the report footer
|
|
rFooter = mReportEngine->rFooter;
|
|
|
|
// Copy the rendering state
|
|
currY = mReportEngine->currY;
|
|
currHeight = mReportEngine->currHeight;
|
|
currPage = mReportEngine->currPage;
|
|
currDate = mReportEngine->currDate;
|
|
cancelRender = mReportEngine->cancelRender;
|
|
|
|
// Copy grand totals list
|
|
grandTotal = mReportEngine->grandTotal;
|
|
m_pageCollection = mReportEngine->m_pageCollection;
|
|
m_needRegeneration = mReportEngine->m_needRegeneration;
|
|
if ( m_pageCollection )
|
|
m_pageCollection->addRef();
|
|
}
|
|
|
|
}
|
|
|
|
#include "mreportengine.moc"
|