kchart

KDChartCustomBox.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 #include <qpainter.h>
00030 #include <qregion.h>
00031 #include <qpalette.h>
00032 #include <qpoint.h>
00033 #include <qsimplerichtext.h>
00034 #include <qpaintdevicemetrics.h>
00035 
00036 #include <KDChartCustomBox.h>
00037 #include <KDXMLTools.h>
00038 #include <KDFrame.h>
00039 
00040 
00041 
00042 KDChartCustomBox::~KDChartCustomBox()
00043 {
00044     // Intentionally left blank for now.
00045 }
00046 
00047 
00048 void KDChartCustomBox::deepCopy( const KDChartCustomBox* source )
00049 {
00050     if( !source || this == source )
00051         return;
00052     _rotation              = source->_rotation;
00053     _content.deepCopy( &source->_content);
00054     _fontSize              = source->_fontSize;
00055     _fontScaleGlobal       = source->_fontScaleGlobal;
00056     _deltaX                = source->_deltaX;
00057     _deltaY                = source->_deltaY;
00058     _width                 = source->_width;
00059     _height                = source->_height;
00060     _color                 = source->_color;
00061     _paper                 = source->_paper;
00062     _anchorArea            = source->_anchorArea;
00063     _anchorPos             = source->_anchorPos;
00064     _anchorAlign           = source->_anchorAlign;
00065     _dataRow               = source->_dataRow;
00066     _dataCol               = source->_dataCol;
00067     _data3rd               = source->_data3rd;
00068     _deltaAlign            = source->_deltaAlign;
00069     _deltaScaleGlobal      = source->_deltaScaleGlobal;
00070     _anchorBeingCalculated = source->_anchorBeingCalculated;
00071 }
00072 
00073 const KDChartCustomBox* KDChartCustomBox::clone() const
00074 {
00075     KDChartCustomBox* newBox = new KDChartCustomBox();
00076     newBox->deepCopy( this );
00077     return newBox;
00078 }
00079 
00080 
00081 float KDChartCustomBox::trueFontSize( double areaWidthP1000,
00082                                       double areaHeightP1000,
00083                                       int rectHeight ) const
00084 {
00085     float size;
00086     if( 0 > _fontSize ) {
00087       if( _fontScaleGlobal ) {
00088 
00089         size = _fontSize * QMIN(areaWidthP1000, areaHeightP1000) * -1.0;//(areaWidthP1000 + areaHeightP1000) / -2.0;
00090 
00091       }  else {
00092              
00093             // calculate the exact size:
00094     float targetLineSpacing = (_fontSize * rectHeight)/ -1000;
00095             size = targetLineSpacing;
00096             // step #1  -  try to make the right font size:
00097             QFont font( content().font() );
00098             font.setPointSizeFloat( size );
00099             QFontMetrics fm( font );
00100         //qDebug(QString("\nsize                   : ")+QString::number(size));
00101         //qDebug(QString("(float)rectHeight      : ")+QString::number((float)rectHeight));
00102         //qDebug(QString("(float)fm.lineSpacing(): ")+QString::number((float)fm.lineSpacing()));
00103             size *= targetLineSpacing / fm.lineSpacing();
00104         //qDebug(QString("size                   : ")+QString::number(size));
00105             // step #2  -  make sure the font size is not too big:
00106             font.setPointSizeFloat( size );
00107             QFontMetrics fm2( font );
00108             size *= targetLineSpacing / fm2.lineSpacing();
00109         //qDebug(QString("(float)rectHeight      : ")+QString::number((float)rectHeight));
00110         //qDebug(QString("(float)fm.lineSpacing(): ")+QString::number((float)fm.lineSpacing()));
00111         //qDebug(QString("size                   : ")+QString::number(size));
00112         }
00113     }
00114     else {
00115 //qDebug(QString("\n_fontsize: ")+QString::number(_fontSize));
00116         if( _fontSize )
00117             size = _fontSize;
00118         else{
00119             size = content().font().pointSize();
00120             if( -1 == size )
00121                 size = content().font().pixelSize();
00122             if( -1 == size )
00123                 size = 10;
00124         }
00125     }
00126     return size;
00127 }
00128 
00129 
00130 int KDChartCustomBox::trueFontLineSpacing( double areaWidthP1000,
00131                                            double areaHeightP1000,
00132                                            int rectHeight ) const
00133 {
00134     QFont font( content().font() );
00135     font.setPointSizeFloat( trueFontSize( areaWidthP1000,areaHeightP1000, rectHeight ) );
00136     QFontMetrics fm( font );
00137     return fm.lineSpacing();
00138 }
00139 
00140 
00141 void KDChartCustomBox::getTrueShift( double areaWidthP1000,
00142                                      double areaHeightP1000,
00143                                      int rectHeight,
00144                                      int& dX,
00145                                      int& dY ) const
00146 {
00147     int x, y;
00148     if( _deltaScaleGlobal ){
00149         x = (0 > _deltaX) ? static_cast < int > ( -areaWidthP1000  * _deltaX ) : _deltaX;
00150         y = (0 > _deltaY) ? static_cast < int > ( -areaHeightP1000 * _deltaY ) : _deltaY;
00151     }else{
00152         int fontHeight = trueFontLineSpacing( areaWidthP1000, areaHeightP1000, rectHeight );
00153         //qDebug("\nfontHeight %i",fontHeight);
00154         x = (0 > _deltaX) ? static_cast < int > ( fontHeight * _deltaX / -100.0 ) : _deltaX;
00155         y = (0 > _deltaY) ? static_cast < int > ( fontHeight * _deltaY / -100.0 ) : _deltaY;
00156         //qDebug("y %i",y);
00157     }
00158     uint deltaAlign = (KDCHART_AlignAuto == _deltaAlign) ? _anchorAlign : _deltaAlign;
00159     if (      Qt::AlignLeft  == (Qt::AlignLeft  & deltaAlign) )
00160         dX = x;
00161     else if ( Qt::AlignRight == (Qt::AlignRight & deltaAlign) )
00162         dX = -x;
00163     else
00164         dX = 0; //  <--  so the _deltaX value becomes ineffective!
00165 
00166     if (      Qt::AlignTop    == (Qt::AlignTop    & deltaAlign) )
00167         dY = y;
00168     else if ( Qt::AlignBottom == (Qt::AlignBottom & deltaAlign) )
00169         dY = -y;
00170     else
00171         dY = 0; //  <--  so the _deltaY value becomes ineffective!
00172 }
00173 
00174 //static QPainter* pppainter=0;
00175 //static int pdWidth =1280;
00176 //static int pdHeight =1024;
00177 
00178 QRect KDChartCustomBox::trueRect( QPoint anchor, double areaWidthP1000, double areaHeightP1000 ) const
00179 {
00180    int w = (0 > _width ) ? static_cast < int > ( -areaWidthP1000  * _width  ) : _width;
00181    int h = (0 > _height) ? static_cast < int > ( -areaHeightP1000 * _height ) : _height;
00182 
00183    //qDebug("w: %i    h: %i", w,h );
00184   
00185     if( _fontScaleGlobal && 0 == w && 0 == h ){
00186       //Now calculate the size of the box based upon the content!
00187         QFont font( content().font() );
00188         if ( _fontSize ) {
00189             font.setPointSizeFloat(
00190                 (0 > _fontSize)
00191             ? (_fontSize * QMIN(areaWidthP1000, areaHeightP1000) * -1.0)//(areaWidthP1000 + areaHeightP1000) / -2.0
00192             : _fontSize );
00193         //qDebug("\n_fontSize * QMIN(areaWidthP1000, areaHeightP1000)    %i * QMIN(%f, %f) text: %s", _fontSize , areaWidthP1000, areaHeightP1000, content().text().latin1());
00194         }
00195         QString txt(     content().text() );
00196         QString txtTest( txt.stripWhiteSpace().lower() );
00197 #if QT_VERSION >= 200 && QT_VERSION < 300
00198 // version 2.x
00199         if( !(txtTest.left(4) == "<qt>") )
00200             txt.prepend(        "<qt>" );
00201         if( !(txtTest.right(5)== "</qt>"))
00202             txt.append(         "</qt>");
00203 #else
00204         if( !txtTest.startsWith("<qt>" ) )
00205             txt.prepend(        "<qt>" );
00206         if( !txtTest.endsWith(  "</qt>") )
00207             txt.append(         "</qt>");
00208 #endif
00209 
00210         //qDebug("\nw: %i    h: %i", w,h );
00211         QSimpleRichText tmpContent( txt, font );
00212 //        tmpContent.setWidth(pdWidth);
00213 //        tmpContent.setHeight(pdHeight);
00214 //        tmpContent.adjustSize();
00215 //        if( pppainter ){
00216 //            tmpContent.setWidth(pppainter, 2000);
00217 //            tmpContent.adjustSize();
00218 //        }
00219         w = tmpContent.widthUsed();
00220         h = tmpContent.height();
00221     //qDebug("pdWidth: %i               w: %i  h %i",pdWidth,w,h);
00222         //qDebug("w: %i    h: %i", w,h );
00223     }
00224 
00225     //qDebug("\nw: %i    h: %i", w,h );
00226     int x,y;
00227     if (      Qt::AlignLeft  == (Qt::AlignLeft  & _anchorAlign) )
00228         x = 0;
00229     else if ( Qt::AlignRight == (Qt::AlignRight & _anchorAlign) )
00230         x = - w + 1;
00231     else
00232         x = - w / 2;
00233 
00234     if (      Qt::AlignTop    == (Qt::AlignTop    & _anchorAlign) )
00235         y = 0;
00236     else if ( Qt::AlignBottom == (Qt::AlignBottom & _anchorAlign) )
00237         y = - h + 1;
00238     else
00239         y = - h / 2;
00240     int dX,dY;
00241     getTrueShift( areaWidthP1000, areaHeightP1000, h,
00242                   dX, dY );
00243     //qDebug("trueRect:  x %i  y %i    w %i  h %i text: %s", anchor.x()+x+dX, anchor.y()+y+dY, w,h, content().text().latin1());
00244     
00245     return QRect( anchor.x()+x+dX, anchor.y()+y+dY, w, h );
00246 }
00247 
00248 
00249 int KDChartCustomBox::trueRectAlignX(const QRect& rect) const
00250 {
00251     int ret = rect.center().x();
00252     if (      Qt::AlignLeft  == (Qt::AlignLeft  & _anchorAlign) )
00253         ret -= rect.width();
00254     else if ( Qt::AlignRight == (Qt::AlignRight & _anchorAlign) )
00255         ret += rect.width();
00256     return ret;
00257 }
00258 int KDChartCustomBox::trueRectAlignY(const QRect& rect) const
00259 {
00260     int ret = rect.center().y();
00261     if (      Qt::AlignTop    == (Qt::AlignTop    & _anchorAlign) )
00262         ret -= rect.height();
00263     else if ( Qt::AlignBottom == (Qt::AlignBottom & _anchorAlign) )
00264         ret += rect.height();
00265     return ret;
00266 }
00267 
00268 void KDChartCustomBox::paint( QPainter* painter,
00269                               QPoint anchor,
00270                               double areaWidthP1000,
00271                               double areaHeightP1000,
00272                               const KDFrame* frame,
00273                               const QRect&   frameRect,
00274                               const QColor * color,
00275                               const QBrush * paper ) const
00276 {
00277     painter->save();
00278     int rotDX = 0;
00279     int rotDY = 0;
00280 /*
00281 //pppainter=painter;
00282 const QPaintDeviceMetrics metrics(painter->device());
00283 pdWidth = metrics.width();
00284 const int aWidthP1000  = metrics.width() /1000;
00285 const int aHeightP1000 = metrics.height()/1000;
00286 //pdHeight = metrics.height();
00287 */
00288 
00289     QRect myRect( trueRect( anchor, areaWidthP1000, areaHeightP1000 ) );
00290     
00291     
00292     /*
00293 QPaintDeviceMetrics metrics(painter->device());
00294 int pdWidth = metrics.width();
00295 int dpiY = metrics.logicalDpiY();
00296 int dpiX = metrics.logicalDpiX();
00297 qDebug("dpiY: %i    dpiX: %i",dpiY,dpiX);
00298 qDebug("pdWidth: %i    box myRect w: %i  h %i",pdWidth,myRect.width(),myRect.height());
00299     */
00300 //myRect.setSize(myRect.size()*6);
00301 
00302 
00303     QRect myFrameRect( frameRect );
00304     if ( myRect.isValid() ) {
00305 //qDebug("box myRect center:  x %i  y %i",myRect.center().x(),myRect.center().y());
00306         if( _rotation ){
00307             getTrueShift( areaWidthP1000, areaHeightP1000, myRect.height(),
00308                           rotDX, rotDY );
00309             myRect.moveBy( -rotDX, -rotDY );
00310             if( frame ) 
00311                 myFrameRect.moveBy( -rotDX, -rotDY );
00312 //qDebug("\nrotDelta:  x %i  y %i",rotDX,rotDY);
00313 //qDebug("\nbox myRect center:  x %i  y %i",myRect.center().x(),myRect.center().y());
00314             myRect.moveCenter( QPoint( anchor.x() - trueRectAlignX(myRect),
00315                                        anchor.y() - trueRectAlignY(myRect) ) );
00316             if( frame )
00317                 myFrameRect.moveCenter( QPoint( anchor.x() - trueRectAlignX(myFrameRect),
00318                                                 anchor.y() - trueRectAlignY(myFrameRect) ) );
00319 //qDebug("box myRect center:  x %i  y %i",myRect.center().x(),myRect.center().y());
00320             painter->translate( anchor.x(), anchor.y() );
00321             painter->rotate( _rotation );
00322             painter->translate( rotDX, rotDY );
00323         }
00324         if( frame )
00325             frame->paint( painter, KDFrame::PaintAll, myFrameRect );
00326         if ( _fontSize ) {
00327       QFont font( content().font() );
00328           
00329           float trueSize = trueFontSize(areaWidthP1000,areaHeightP1000, myRect.height() );
00330           font.setPointSizeFloat( trueSize );  
00331           //adjust the area height related to the font size 
00332           myRect.setHeight( (int)(trueSize )+ (int)(trueSize*0.5));     
00333       const KDChartTextPiece tmpTextPiece( painter, content().text(), font );
00334           
00335       tmpTextPiece.draw( painter, myRect.x(), myRect.y(), myRect,
00336                  color ? *color :  _color,
00337                  paper ?  paper : &_paper );
00338         }else{
00339       
00340       content().draw( painter, myRect.x(), myRect.y(), myRect,
00341               color ? *color :  _color,
00342               paper ?  paper : &_paper );
00343         }
00344     }
00345     painter->restore();
00346 }
00347 
00348 
00349 void KDChartCustomBox::createCustomBoxNode( QDomDocument& document,
00350         QDomNode& parent,
00351         const QString& elementName,
00352         const KDChartCustomBox* custombox )
00353 {
00354     QDomElement customBoxElement = document.createElement( elementName );
00355     parent.appendChild( customBoxElement );
00356     KDXML::createIntNode( document, parent, "Rotation", custombox->_rotation );
00357     KDXML::createStringNode( document, parent, "ContentText",
00358             custombox->_content.text() );
00359     KDXML::createFontNode( document, parent, "ContentFont",
00360             custombox->_content.font() );
00361     KDXML::createIntNode( document, parent, "FontSize", custombox->_fontSize );
00362     KDXML::createBoolNode( document, parent, "FontScaleGlobal",
00363             custombox->_fontScaleGlobal );
00364     KDXML::createIntNode( document, parent, "DeltaX", custombox->_deltaX );
00365     KDXML::createIntNode( document, parent, "DeltaY", custombox->_deltaY );
00366     KDXML::createIntNode( document, parent, "Width", custombox->_width );
00367     KDXML::createIntNode( document, parent, "Height", custombox->_height );
00368     KDXML::createColorNode( document, parent, "Color", custombox->_color );
00369     KDXML::createBrushNode( document, parent, "Paper", custombox->_paper );
00370     KDXML::createIntNode( document, parent, "AnchorArea",
00371             custombox->_anchorArea );
00372     KDXML::createStringNode( document, parent, "AnchorPos",
00373             KDChartEnums::positionFlagToString( custombox->_anchorPos ) );
00374     KDXML::createIntNode( document, parent, "AnchorAlign",
00375             custombox->_anchorAlign );
00376     KDXML::createIntNode( document, parent, "DataRow",
00377             custombox->_dataRow );
00378     KDXML::createIntNode( document, parent, "DataCol",
00379             custombox->_dataCol );
00380     KDXML::createIntNode( document, parent, "Data3rd",
00381             custombox->_data3rd );
00382     KDXML::createIntNode( document, parent, "DeltaAlign",
00383             custombox->_deltaAlign );
00384     KDXML::createBoolNode( document, parent, "DeltaScaleGlobal",
00385             custombox->_deltaScaleGlobal );
00386 }
00387 
00388 
00389 bool KDChartCustomBox::readCustomBoxNode( const QDomElement& element,
00390         KDChartCustomBox& custombox )
00391 {
00392     bool ok = true;
00393     QString tempContentText;
00394     QFont tempContentFont;
00395     int tempRotation = 0; // must be initialized: new parameter, not present in old versions of KDChart
00396     int tempDeltaAlign = KDCHART_AlignAuto; // must be initialized too: new parameter
00397     bool tempDeltaScaleGlobal = true;   // must be initialized too: new parameter
00398     int tempFontSize, tempDeltaX, tempDeltaY,
00399     tempWidth, tempHeight, tempAnchorArea, tempAnchorAlign,
00400     tempDataRow, tempDataCol, tempData3rd;
00401     bool tempFontScaleGlobal;
00402     QColor tempColor;
00403     QBrush tempPaper;
00404     KDChartEnums::PositionFlag tempAnchorPos = KDChartEnums::PosTopLeft;
00405     QDomNode node = element.firstChild();
00406     while( !node.isNull() ) {
00407         QDomElement element = node.toElement();
00408         if( !element.isNull() ) { // was really an element
00409             QString tagName = element.tagName();
00410             if( tagName == "Rotation" ) {
00411                 ok = ok & KDXML::readIntNode( element, tempRotation );
00412             } else if( tagName == "ContentText" ) {
00413                 ok = ok & KDXML::readStringNode( element, tempContentText );
00414             } else if( tagName == "ContentFont" ) {
00415                 ok = ok & KDXML::readFontNode( element, tempContentFont );
00416             } else if( tagName == "FontSize" ) {
00417                 ok = ok & KDXML::readIntNode( element, tempFontSize );
00418             } else if( tagName == "FontScaleGlobal" ) {
00419                 ok = ok & KDXML::readBoolNode( element, tempFontScaleGlobal );
00420             } else if( tagName == "DeltaX" ) {
00421                 ok = ok & KDXML::readIntNode( element, tempDeltaX );
00422             } else if( tagName == "DeltaY" ) {
00423                 ok = ok & KDXML::readIntNode( element, tempDeltaY );
00424             } else if( tagName == "Width" ) {
00425                 ok = ok & KDXML::readIntNode( element, tempWidth );
00426             } else if( tagName == "Height" ) {
00427                 ok = ok & KDXML::readIntNode( element, tempHeight );
00428             } else if( tagName == "Color" ) {
00429                 ok = ok & KDXML::readColorNode( element, tempColor );
00430             } else if( tagName == "Paper" ) {
00431                 ok = ok & KDXML::readBrushNode( element, tempPaper );
00432             } else if( tagName == "AnchorArea" ) {
00433                 ok = ok & KDXML::readIntNode( element, tempAnchorArea );
00434             } else if( tagName == "AnchorPos" ) {
00435                 QString value;
00436                 ok = ok & KDXML::readStringNode( element, value );
00437                 tempAnchorPos = KDChartEnums::stringToPositionFlag( value );
00438             } else if( tagName == "AnchorAlign" ) {
00439                 ok = ok & KDXML::readIntNode( element, tempAnchorAlign );
00440             } else if( tagName == "DataRow" ) {
00441                 ok = ok & KDXML::readIntNode( element, tempDataRow );
00442             } else if( tagName == "DataCol" ) {
00443                 ok = ok & KDXML::readIntNode( element, tempDataCol );
00444             } else if( tagName == "Data3rd" ) {
00445                 ok = ok & KDXML::readIntNode( element, tempData3rd );
00446             } else if( tagName == "DeltaAlign" ) {
00447                 ok = ok & KDXML::readIntNode( element, tempDeltaAlign );
00448             } else if( tagName == "DeltaScaleGlobal" ) {
00449                 ok = ok & KDXML::readBoolNode( element, tempDeltaScaleGlobal );
00450             } else {
00451                 qDebug( "Unknown tag in custom box" );
00452             }
00453         }
00454         node = node.nextSibling();
00455     }
00456 
00457     if( ok ) {
00458         const KDChartTextPiece piece( 0, tempContentText, tempContentFont );
00459         custombox._content.deepCopy( &piece );
00460         custombox._rotation = tempRotation;
00461         custombox._fontSize = tempFontSize;
00462         custombox._fontScaleGlobal = tempFontScaleGlobal;
00463         custombox._deltaX = tempDeltaX;
00464         custombox._deltaY = tempDeltaY;
00465         custombox._width = tempWidth;
00466         custombox._height = tempHeight;
00467         custombox._color = tempColor;
00468         custombox._paper = tempPaper;
00469         custombox._anchorArea = tempAnchorArea;
00470         custombox._anchorPos = tempAnchorPos;
00471         custombox._anchorAlign = tempAnchorAlign;
00472         custombox._dataRow = tempDataRow;
00473         custombox._dataCol = tempDataCol;
00474         custombox._data3rd = tempData3rd;
00475         custombox._deltaAlign       = tempDeltaAlign;
00476         custombox._deltaScaleGlobal = tempDeltaScaleGlobal;
00477     }
00478 
00479     return ok;
00480 }
00481 
00482 #include "KDChartCustomBox.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys