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