kchart

KDChart.cpp

00001 /* -*- Mode: C++ -*-
00002    KDChart - a multi-platform charting engine
00003    */
00004 
00005 /****************************************************************************
00006  ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB.  All rights reserved.
00007  **
00008  ** This file is part of the KDChart library.
00009  **
00010  ** This file may be distributed and/or modified under the terms of the
00011  ** GNU General Public License version 2 as published by the Free Software
00012  ** Foundation and appearing in the file LICENSE.GPL included in the
00013  ** packaging of this file.
00014  **
00015  ** Licensees holding valid commercial KDChart licenses may use this file in
00016  ** accordance with the KDChart Commercial License Agreement provided with
00017  ** the Software.
00018  **
00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021  **
00022  ** See http://www.klaralvdalens-datakonsult.se/?page=products for
00023  **   information about KDChart Commercial License Agreements.
00024  **
00025  ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
00026  ** licensing are not clear to you.
00027  **
00028  **********************************************************************/
00029 #if defined KDAB_EVAL
00030 #include "../evaldialog/evaldialog.h"
00031 #endif
00032 
00036 #include <KDChart.h>
00037 #include <KDChartPainter.h>
00038 #include <KDChartParams.h>
00039 #include <KDChartGlobal.h>
00040 #include <KDChartAxisParams.h>
00041 
00042 #include <qglobal.h>
00043 #include <qpainter.h>
00044 #include <qpaintdevice.h>
00045 #include <qpaintdevicemetrics.h>
00046 
00047 #ifdef QSA
00048 #if 0   // Disabled by ingwa to make it compile
00049 #include <qsinterpreter.h>
00050 #include "KDChartWrapperFactory.h"
00051 #include "KDChartObjectFactory.h"
00052 #endif
00053 #endif
00054 
00075 KDChartParams* KDChart::oldParams = 0;
00076 KDChartPainter* KDChart::cpainter = 0;
00077 KDChartPainter* KDChart::cpainter2 = 0;
00078 KDChartParams::ChartType KDChart::cpainterType = KDChartParams::NoType;
00079 KDChartParams::ChartType KDChart::cpainterType2 = KDChartParams::NoType;
00080 
00085 void cleanupPainter();
00086 
00087 
00088 bool hasCartesianAxes( KDChartParams::ChartType chartType )
00089 {
00090     switch( chartType ){
00091         case KDChartParams::NoType:     return false;
00092         case KDChartParams::Bar:        return true;
00093         case KDChartParams::Line:       return true;
00094         case KDChartParams::Area:       return true;
00095         case KDChartParams::Pie:        return false;
00096         case KDChartParams::HiLo:       return true;
00097         case KDChartParams::Ring:       return false;
00098         case KDChartParams::Polar:      return false; // Polar axes are NO cartesian axes!
00099         case KDChartParams::BoxWhisker: return true;
00100         default:
00101                                         qDebug("\n\n\n\nKDCHART ERROR: Type missing in KDChart.cpp hasCartesianAxes()\n"
00102                                                 "=============================================================\n"
00103                                                 "=============================================================\n\n\n\n");
00104     }
00105     return false;
00106 }
00107 
00108 
00122 bool KDChart::painterToDrawRect( QPainter* painter, QRect& drawRect )
00123 {
00124     if( painter ){
00125         QPaintDeviceMetrics painterMetrics( painter->device() );
00126         drawRect = QRect( 0, 0, painterMetrics.width(), painterMetrics.height() );
00127         drawRect.setWidth(  drawRect.width() -2 );
00128         drawRect.setHeight( drawRect.height()-2 );
00129         return true;
00130     }else{
00131         drawRect = QRect( QPoint(0,0), QSize(0,0) );
00132         qDebug("ERROR: KDChartPainter::painterToDrawRect() was called with *no* painter.");
00133         return false;
00134     }
00135 }
00136 
00137 
00156 bool KDChart::setupGeometry( QPainter* painter,
00157                              KDChartParams* params,
00158                              KDChartTableDataBase* data,
00159                              const QRect& drawRect )
00160 {
00161 //qDebug("INVOKING: KDChart::setupGeometry()");
00162     if( !params ){
00163         qDebug("ERROR: setupGeometry::paint() was called with *no* params.");
00164         return false;
00165     }
00166     if( !data ){
00167         qDebug("ERROR: setupGeometry::paint() was called with *no* data.");
00168         return false;
00169     }
00170     // don't crash due to memory problems when running on windows
00171 #ifdef Q_WS_WIN
00172     QPixmap::setDefaultOptimization(QPixmap::MemoryOptim);
00173 #endif
00174 
00175     // Install a cleanup routine that is called when the Qt
00176     // application shuts down and cleans up any potentially still
00177     // existing painters. Only do this once.
00178     static bool bFirstCleanUpInstall = true;
00179     if( bFirstCleanUpInstall ) {
00180         bFirstCleanUpInstall = false;
00181         qAddPostRoutine( cleanupPainter );
00182     }
00183 
00184     // Check whether last call of this methode gave us the same params pointer.
00185     // If params changed we must create new painter(s).
00186     bool paramsHasChanged = ( params != oldParams );
00187     if( paramsHasChanged )
00188         oldParams = params;
00189 
00190     // Check whether there already is painter and, if that is the
00191     // case, whether the painter still has the correct type (the chart
00192     // type might have changed in the meantime).
00193     if ( paramsHasChanged || !cpainter || cpainterType != params->chartType() )
00194     {
00195         delete cpainter; /* save, since always 0 if there was not yet
00196                             a chart painter */
00197         // create a new painter
00198         cpainter = KDChartPainter::create( params, false );
00199         cpainterType = params->chartType();
00200     }
00201 
00202     // Check whether there already is a 2nd painter and, if that is the
00203     // case, whether the painter still has the correct type (the
00204     // additional chart type might have changed in the meantime).
00205     if ( paramsHasChanged || !cpainter2 || cpainterType2 != params->additionalChartType() )
00206     {
00207         delete cpainter2; /* save, since always 0 if there was not yet
00208                              a chart painter */
00209         // create a new painter
00210         if( hasCartesianAxes( params->chartType() )
00211                 && hasCartesianAxes( params->additionalChartType() ) ){
00212             cpainter2 = KDChartPainter::create( params, true );
00213             cpainterType2 = params->additionalChartType();
00214         }else{
00215             cpainter2 = 0;
00216             cpainterType2 = KDChartParams::NoType;
00217         }
00218     }
00219 
00220     if ( cpainter ){  // can be 0 if no exceptions are used
00221         cpainter->setupGeometry( painter, data, drawRect );
00222     }
00223 
00224     if ( cpainter2 ){  // can be 0 if no exceptions are used
00225         cpainter2->setupGeometry( painter, data, drawRect );
00226     }
00227 
00228     return true;
00229 }
00230 
00256 void KDChart::paint( QPainter*              painter,
00257                      KDChartParams*         paraParams,
00258                      KDChartTableDataBase*  paraData,
00259                      KDChartDataRegionList* regions,
00260                      const QRect*           rect,
00261                      bool                   mustCalculateGeometry )
00262 {
00263 //qDebug("KDChart::paint() mustCalculateGeometry: "+QString(mustCalculateGeometry?"TRUE":"FALSE") );
00264 #if defined KDAB_EVAL
00265     EvalDialog::checkEvalLicense( "KD Chart" );
00266 #endif
00267 
00268     // delete old contents, to avoid the region from constantly growing
00269     if( regions )
00270         regions->clear();
00271 
00272     KDChartParams*        params = paraParams;
00273     KDChartTableDataBase* data   = paraData;
00274     if( !paraParams && !paraData ){
00275         qDebug("-----");
00276         qDebug("Note:  KDChart::paint() was called without \"params\" and without \"data\".");
00277         qDebug("-----  Showing a default bar chart.");
00278         params = new KDChartParams();
00279         params->setDatasetGap(3 * params->valueBlockGap());
00280         params->setPrintDataValues( false );
00281         params->setLegendPosition( KDChartParams::NoLegend );
00282         params->setAxisLabelsVisible( KDChartAxisParams::AxisPosBottom, false );
00283         params->setAxisShowGrid( KDChartAxisParams::AxisPosBottom, false );
00284         params->setHeader1Text( "KDChartWidget" );
00285         data = new KDChartTableData( 3, 1 );
00286         // 1st series
00287         data->setCell( 0, 0,    12.5   );
00288         // 2nd series
00289         data->setCell( 1, 0,     8.0   );
00290         // 3rd series
00291         data->setCell( 2, 0,    15.0   );
00292     }
00293 
00294     QRect drawRect;
00295     bool bOk = true;
00296     if( mustCalculateGeometry || !cpainter || cpainter->outermostRect().isNull() ){
00297         if( rect )
00298             drawRect = *rect;
00299         else if( !painterToDrawRect( painter, drawRect ) ){
00300             qDebug("ERROR: KDChart::paint() could not calculate a drawing area.");
00301             bOk = false;
00302         }
00303         //qDebug("xxx" );
00304         if( (params || data) && !setupGeometry( painter, params, data, drawRect ) ){
00305             qDebug("ERROR: KDChart::paint() could not calculate the chart geometry.");
00306             bOk = false;
00307         }
00308     }else{
00309         drawRect = cpainter->outermostRect();
00310     }
00311 
00312     //qDebug("yyy" );
00313 
00314     if( bOk ){
00315         // Note: the following *must* paint the main-chart first
00316         //       and the additional chart afterwards
00317         //       since all axes computations are only done when
00318         //       the first chart is painted but will be needed for both of course.
00319         //
00320         bool paintFirst = true;
00321         bool paintLast  = ! ( cpainter && cpainter2 );
00322         if ( cpainter ) {  // can be 0 if no exceptions are used
00323             //qDebug("zzz" );
00324             cpainter->paint( painter, data, paintFirst, paintLast, regions, &drawRect, false );
00325 
00326             paintFirst = false;
00327         }
00328         paintLast = true;
00329         if ( cpainter2 )   // can be 0 if no exceptions are used
00330             cpainter2->paint( painter, data, paintFirst, paintLast, regions, &drawRect, false );
00331     }
00332 
00333     if( !paraParams && !paraData ){
00334         delete params;
00335         delete data;
00336     }
00337     KDChartAutoColor::freeInstance(); // stuff that memory leak
00338 }
00339 
00340 
00354 void KDChart::print( QPainter* painter, KDChartParams* params,
00355         KDChartTableDataBase* data,
00356         KDChartDataRegionList* regions,
00357         const QRect* rect,
00358         bool mustCalculateGeometry )
00359 {
00360     bool oldOpt=true;
00361     if( params ){
00362         oldOpt = params->optimizeOutputForScreen();
00363         params->setOptimizeOutputForScreen( false );
00364     }
00365     paint( painter, params, data, regions, rect, mustCalculateGeometry );
00366     if( params )
00367         params->setOptimizeOutputForScreen( oldOpt );
00368 }
00369 
00370 
00371 /*
00372    This method is called at application shut-down and cleans up the
00373    last created painter.
00374    */
00375 void cleanupPainter()
00376 {
00377     delete KDChart::cpainter;
00378     delete KDChart::cpainter2;
00379     KDChart::oldParams = 0;
00380 }
00381 
00382 #ifdef QSA
00383 void KDChart::initInterpreter( QSInterpreter* interpreter )
00384 {
00385     privateInitInterpreter( interpreter );
00386     interpreter->evaluate( globals() );
00387 }
00388 
00389 void KDChart::initProject( QSProject* project )
00390 {
00391     project->createScript( QString::fromLatin1( "KDCHART_Globals" ), globals() );
00392     privateInitInterpreter( project->interpreter() );
00393 }
00394 
00395 QString KDChart::globals()
00396 {
00397     QString globals;
00398     QMap<char*, double> intMap;
00399 
00400     intMap.insert( "KDCHART_POS_INFINITE", KDCHART_POS_INFINITE );
00401     intMap.insert( "KDCHART_NEG_INFINITE", KDCHART_NEG_INFINITE );
00402     intMap.insert( "KDCHART_AlignAuto", KDCHART_AlignAuto );
00403     intMap.insert( "KDCHART_ALL_AXES", KDCHART_ALL_AXES );
00404     intMap.insert( "KDCHART_NO_AXIS", KDCHART_NO_AXIS );
00405     intMap.insert( "KDCHART_ALL_DATASETS", KDCHART_ALL_DATASETS );
00406     intMap.insert( "KDCHART_NO_DATASET", KDCHART_NO_DATASET );
00407     intMap.insert( "KDCHART_UNKNOWN_CHART", KDCHART_UNKNOWN_CHART );
00408     intMap.insert( "KDCHART_ALL_CHARTS", KDCHART_ALL_CHARTS );
00409     intMap.insert( "KDCHART_NO_CHART", KDCHART_NO_CHART );
00410     intMap.insert( "KDCHART_GLOBAL_LINE_STYLE", KDCHART_GLOBAL_LINE_STYLE );
00411     intMap.insert( "KDCHART_AUTO_SIZE", KDCHART_AUTO_SIZE );
00412     intMap.insert( "KDCHART_DATA_VALUE_AUTO_DIGITS", KDCHART_DATA_VALUE_AUTO_DIGITS );
00413     intMap.insert( "KDCHART_SAGITTAL_ROTATION", KDCHART_SAGITTAL_ROTATION );
00414     intMap.insert( "KDCHART_TANGENTIAL_ROTATION", KDCHART_TANGENTIAL_ROTATION );
00415     intMap.insert( "KDCHART_PROPSET_NORMAL_DATA", KDCHART_PROPSET_NORMAL_DATA );
00416     intMap.insert( "KDCHART_PROPSET_TRANSPARENT_DATA", KDCHART_PROPSET_TRANSPARENT_DATA );
00417     intMap.insert( "KDCHART_PROPSET_HORI_LINE", KDCHART_PROPSET_HORI_LINE );
00418     intMap.insert( "KDCHART_PROPSET_VERT_LINE", KDCHART_PROPSET_VERT_LINE );
00419     intMap.insert( "KDCHART_SAGGITAL_ROTATION", KDCHART_SAGGITAL_ROTATION );
00420     intMap.insert( "KDCHART_CNT_ORDINATES", KDCHART_CNT_ORDINATES );
00421     intMap.insert( "KDCHART_MAX_POLAR_DELIMS_AND_LABELS_POS", KDCHART_MAX_POLAR_DELIMS_AND_LABELS_POS );
00422     intMap.insert( "KDCHART_MAX_AXES", KDCHART_MAX_AXES );
00423     intMap.insert( "KDCHART_AXIS_LABELS_AUTO_DELTA", KDCHART_AXIS_LABELS_AUTO_DELTA );
00424     intMap.insert( "KDCHART_AXIS_LABELS_AUTO_LEAVEOUT", KDCHART_AXIS_LABELS_AUTO_LEAVEOUT );
00425     intMap.insert( "KDCHART_AXIS_LABELS_AUTO_DIGITS", KDCHART_AXIS_LABELS_AUTO_DIGITS );
00426     intMap.insert( "KDCHART_AXIS_GRID_AUTO_LINEWIDTH", KDCHART_AXIS_GRID_AUTO_LINEWIDTH );
00427     intMap.insert( "KDCHART_AXIS_IGNORE_EMPTY_INNER_SPAN", KDCHART_AXIS_IGNORE_EMPTY_INNER_SPAN );
00428     intMap.insert( "KDCHART_DONT_CHANGE_EMPTY_INNER_SPAN_NOW", KDCHART_DONT_CHANGE_EMPTY_INNER_SPAN_NOW );
00429     intMap.insert( "DBL_MIN", DBL_MIN );
00430     intMap.insert( "DBL_MAX", DBL_MAX );
00431 
00432     for( QMapIterator<char*,double> it= intMap.begin(); it != intMap.end(); ++it ) {
00433         // This is written this way to be efficient
00434         globals += QString::fromLatin1( "const " );
00435         globals += it.key();
00436         globals += " = ";
00437         globals += QString::number( it.data() );
00438         globals += ";\n";
00439     }
00440 
00441     globals += QString::fromLatin1( "const KDCHART_AXIS_LABELS_AUTO_DATETIME_FORMAT=\"%1\";\n" )
00442                .arg( QString::fromLatin1( KDCHART_AXIS_LABELS_AUTO_DATETIME_FORMAT ) );
00443     globals += QString::fromLatin1( "const KDCHART_AXIS_LABELS_AUTO_LIMIT = 140319.64;\n" );
00444     globals += QString::fromLatin1( "const KDCHART_DEFAULT_AXIS_GRID_COLOR = new Color(\"%1\");\n" )
00445                .arg(KDCHART_DEFAULT_AXIS_GRID_COLOR.name());
00446     globals += QString::fromLatin1( "const KDCHART_DATA_VALUE_AUTO_COLOR = new Color(\"%1\");\n" )
00447                .arg( (KDCHART_DATA_VALUE_AUTO_COLOR)->name());
00448 
00449 
00450     QMap<char*,QColor> colorMap;
00451     colorMap.insert( "Qt.color0", Qt::color0 );
00452     colorMap.insert( "Qt.color1", Qt::color1 );
00453     colorMap.insert( "Qt.black", Qt::black );
00454     colorMap.insert( "Qt.white", Qt::white );
00455     colorMap.insert( "Qt.darkGray", Qt::darkGray );
00456     colorMap.insert( "Qt.gray", Qt::gray );
00457     colorMap.insert( "Qt.lightGray", Qt::lightGray );
00458     colorMap.insert( "Qt.red", Qt::red );
00459     colorMap.insert( "Qt.green", Qt::green );
00460     colorMap.insert( "Qt.blue", Qt::blue );
00461     colorMap.insert( "Qt.cyan", Qt::cyan );
00462     colorMap.insert( "Qt.magenta", Qt::magenta );
00463     colorMap.insert( "Qt.yellow", Qt::yellow );
00464     colorMap.insert( "Qt.darkRed", Qt::darkRed );
00465     colorMap.insert( "Qt.darkGreen", Qt::darkGreen );
00466     colorMap.insert( "Qt.darkBlue", Qt::darkBlue );
00467     colorMap.insert( "Qt.darkCyan", Qt::darkCyan );
00468     colorMap.insert( "Qt.darkMagenta", Qt::darkMagenta );
00469     colorMap.insert( "Qt.darkYellow", Qt::darkYellow );
00470     for( QMapIterator<char*,QColor> it2= colorMap.begin(); it2 != colorMap.end(); ++it2 ) {
00471         // This is written this way to be efficient
00472         globals += QString::fromLatin1( it2.key() );
00473         globals += QString::fromLatin1( " = new Color( " );
00474         globals += QString::number( it2.data().red() );
00475         globals += ',';
00476         globals += QString::number( it2.data().green() );
00477         globals += ',';
00478         globals += QString::number( it2.data().blue() );
00479         globals += QString::fromLatin1( " );\n" );
00480     }
00481     //qDebug( "%s",globals.latin1() );
00482     return globals;
00483 }
00484 
00485 void KDChart::privateInitInterpreter( QSInterpreter* interpreter )
00486 {
00487     interpreter->addWrapperFactory( new KDChartWrapperFactory );
00488     interpreter->addObjectFactory ( new KDChartObjectFactory );
00489 }
00490 
00491 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys