kchart

kchart_params.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001,2002,2003,2004 Laurent Montel <montel@kde.org>
00003    Copyright (C) 2006 Thorsten Zachmann <zachmann@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 
00022 //#include <stdlib.h>
00023 #include <iostream>
00024 using std::cout;
00025 using std::cerr;
00026 
00027 
00028 #include <dcopobject.h>
00029 #include <klocale.h>
00030 #include <kdebug.h>
00031 
00032 #include <KoXmlNS.h>
00033 #include <KoXmlWriter.h>
00034 #include <KoDom.h>
00035 #include <KoOasisLoadingContext.h>
00036 
00037 #include <qregexp.h>
00038 
00039 #include "kdchart/KDChartParams.h"
00040 #include "kdchart/KDChartAxisParams.h"
00041 
00042 #include "kchart_params.h"
00043 #include "kchart_part.h"
00044 #include "KChartParamsIface.h"
00045 
00046 
00047 namespace KChart
00048 {
00049 
00050 
00051 KChartParams::KChartParams( KChartPart *_part )
00052     : KDChartParams(),
00053       m_part( _part )
00054 {
00055     // Default values for subtypes.
00056     m_firstRowAsLabel = false;
00057     m_firstColAsLabel = false;
00058 
00059     // Default values for OpenDocument extensions.
00060     m_barNumLines     = 0;
00061 
00062     m_dcop = 0;
00063     //dcopObject(); // build it
00064 }
00065 
00066 
00067 KChartParams::~KChartParams()
00068 {
00069     delete m_dcop;
00070 }
00071 
00072 
00073 // ----------------------------------------------------------------
00074 
00075 
00076 QString KChartParams::chartTypeToString( ChartType _type) const
00077 {
00078 #if 0
00079     if (_type == BarLines )
00080     return "BarLines";
00081     else
00082 #endif
00083     return KDChartParams::chartTypeToString( (KDChartParams::ChartType) _type );
00084 }
00085 
00086 
00087 KChartParams::ChartType
00088 KChartParams::stringToChartType( const QString& _string )
00089 {
00090 #if 0
00091     if ( _string == "BarLines" )
00092     return BarLines;
00093     else
00094 #endif
00095     return (ChartType) KDChartParams::stringToChartType( _string );
00096 }
00097 
00098 
00099 void KChartParams::setFirstRowAsLabel( bool _val )
00100 {
00101     m_firstRowAsLabel = _val;
00102 
00103     m_part->doSetData( *m_part->data(),
00104                m_firstRowAsLabel, m_firstColAsLabel );
00105 }
00106 
00107 void KChartParams::setFirstColAsLabel( bool _val )
00108 {
00109     m_firstColAsLabel = _val;
00110 
00111     m_part->doSetData( *m_part->data(),
00112                m_firstRowAsLabel, m_firstColAsLabel );
00113 }
00114 
00115 
00116 DCOPObject* KChartParams::dcopObject()
00117 {
00118     if ( !m_dcop )
00119     m_dcop = new KChartParamsIface( this );
00120     return m_dcop;
00121 }
00122 
00123 
00124 // ================================================================
00125 //                     Loading and Saving
00126 
00127 
00128 
00129 static const struct {
00130     const char              *oasisClass;
00131     KChartParams::ChartType  chartType;
00132 } oasisChartTypes[] = {
00133     { "chart:bar",    KChartParams::Bar },
00134     { "chart:line",   KChartParams::Line },
00135     { "chart:area",   KChartParams::Area },
00136     { "chart:circle", KChartParams::Pie },
00137     //{ "chart:xxx",    KChartParams::HiLo },
00138     //{ "chart:stock",  KChartParams::??? },
00139     //{ "chart:add-in", KChartParams::??? },
00140     //{ "chart:scatter",KChartParams::??? },
00141     { "chart:ring",   KChartParams::Ring },
00142     { "chart:radar",  KChartParams::Polar }
00143     //{ "chart:xxx",    KChartParams::BoxWhisker },
00144 
00145     //{ "chart:xxx",    KChartParams::BarLines },
00146     // FIXME: More?
00147 };
00148 
00149 
00150 static const unsigned int numOasisChartTypes
00151   = sizeof oasisChartTypes / sizeof *oasisChartTypes;
00152 
00153 
00154 #if 0  // Example code!!
00155     KoOasisLoadingContext  loadingContext( this, oasisStyles, store );
00156     KoStyleStack          &styleStack = loadingContext.styleStack();
00157 
00158     styleStack.save();
00159     styleStack.setTypeProperties( "graphic" ); // load graphic-properties
00160     loadingContext.fillStyleStack( chartElem, KoXmlNS::chart, "style-name" );
00161 
00162     const QString fillColor = styleStack.attributeNS( KoXmlNS::draw, "fill-color" );
00163     kdDebug() << "fillColor=" << fillColor << endl;
00164 
00165     styleStack.restore();
00166 #endif
00167 
00168 
00169 // Load the data from an OpenDocument chart:chart element.
00170 
00171 void KChartParams::loadOasisFont( KoOasisLoadingContext& context, QFont& font, QColor& color )
00172 {
00173     KoStyleStack& styleStack = context.styleStack();
00174     styleStack.setTypeProperties( "text" ); // load all style attributes from "style:text-properties"
00175 
00176     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "color" ) ) { // 3.10.3
00177         color.setNamedColor( styleStack.attributeNS( KoXmlNS::fo, "color" ) ); // #rrggbb format
00178     }
00179     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-family" )  // 3.10.9
00180             || styleStack.hasAttributeNS( KoXmlNS::style, "font-name" ) ) { // 3.10.8
00181         // Hmm, the remove "'" could break it's in the middle of the fontname...
00182         QString fontName = styleStack.attributeNS( KoXmlNS::fo, "font-family" ).remove( "'" );
00183         if ( fontName.isEmpty() ) {
00184             // ##### TODO. This is wrong. style:font-name refers to a font-decl entry.
00185             // We have to look it up there, and retrieve _all_ font attributes from it, not just the name.
00186             fontName = styleStack.attributeNS( KoXmlNS::style, "font-name" ).remove( "'" );
00187         }
00188         // 'Thorndale' is not known outside OpenOffice so we substitute it
00189         // with 'Times New Roman' that looks nearly the same.
00190         if ( fontName == "Thorndale" )
00191             fontName = "Times New Roman";
00192 
00193         fontName.remove( QRegExp( "\\sCE$" ) ); // Arial CE -> Arial
00194         font.setFamily( fontName );
00195     }
00196     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-size" ) ) { // 3.10.14
00197         double pointSize = styleStack.fontSize();
00198         font.setPointSizeFloat( pointSize );
00199         kdDebug(35001) << "font size: " << pointSize << endl;
00200     }
00201     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-weight" ) ) { // 3.10.24
00202         QString fontWeight = styleStack.attributeNS( KoXmlNS::fo, "font-weight" );
00203         int boldness;
00204         if ( fontWeight == "normal" )
00205             boldness = 50;
00206         else if ( fontWeight == "bold" )
00207             boldness = 75;
00208         else
00209             // XSL/CSS has 100,200,300...900. Not the same scale as Qt!
00210             // See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight
00211             boldness = fontWeight.toInt() / 10;
00212         font.setWeight( boldness );
00213     }
00214     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-style" ) ) { // 3.10.19
00215         if ( styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "italic" ||
00216              styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "oblique" ) { // no difference in kotext
00217             font.setItalic( true );
00218         }
00219     }
00220 }
00221     
00222 bool KChartParams::loadOasis( const QDomElement     &chartElem,
00223                   KoOasisLoadingContext &loadingContext,
00224                               QString               &errorMessage,
00225                   KoStore               */*store*/ )
00226 {
00227     const QString chartClass = chartElem.attributeNS( KoXmlNS::chart,
00228                               "class", QString::null );
00229     bool          knownType = false;
00230 
00231     // Find out what KChart charttype the OASIS charttype corresponds to.
00232     for ( unsigned int i = 0 ; i < numOasisChartTypes ; ++i ) {
00233         if ( chartClass == oasisChartTypes[i].oasisClass ) {
00234             kdDebug(35001) << "found chart of type " << chartClass << endl;
00235         //cerr << "found chart of type " << chartClass.latin1() << "\n";
00236 
00237             setChartType( oasisChartTypes[i].chartType );
00238             knownType = true;
00239             break;
00240         }
00241     }
00242 
00243     // If we can't find out what charttype it is, we might as well end here.
00244     if ( !knownType ) {
00245         errorMessage = i18n( "Unknown chart type %1" ).arg( chartClass );
00246         kdDebug(35001) << errorMessage << endl;
00247         return false;
00248     }
00249 
00250     // Title TODO (more details, e.g. font, placement etc)
00251     QDomElement titleElem = KoDom::namedItemNS( chartElem,
00252                          KoXmlNS::chart, "title" );
00253     if ( !titleElem.isNull() ) {
00254         loadingContext.styleStack().save();
00255         loadingContext.fillStyleStack( titleElem, KoXmlNS::chart, "style-name", "chart" );
00256         QFont font;
00257         QColor color;
00258         loadOasisFont( loadingContext, font, color );
00259         setHeaderFooterFont( KDChartParams::HdFtPosHeader, font, true, font.pointSize() );
00260         setHeaderFooterColor( KDChartParams::HdFtPosHeader, color );
00261         loadingContext.styleStack().restore();
00262 
00263     QDomElement  pElem = KoDom::namedItemNS( titleElem,
00264                          KoXmlNS::text, "p" );
00265     setHeader1Text( pElem.text() );
00266     }
00267 
00268     // Subtitle TODO (more details)
00269     QDomElement subtitleElem = KoDom::namedItemNS( chartElem, KoXmlNS::chart,
00270                            "subtitle" );
00271     if ( !subtitleElem.isNull() ) {
00272         loadingContext.styleStack().save();
00273         loadingContext.fillStyleStack( subtitleElem, KoXmlNS::chart, "style-name", "chart" );
00274         QFont font;
00275         QColor color;
00276         loadOasisFont( loadingContext, font, color );
00277         setHeaderFooterFont( KDChartParams::HdFtPosHeader2, font, true, font.pointSize() );
00278         setHeaderFooterColor( KDChartParams::HdFtPosHeader2, color );
00279         loadingContext.styleStack().restore();
00280 
00281     QDomElement  pElem = KoDom::namedItemNS( subtitleElem,
00282                          KoXmlNS::text, "p" );
00283     setHeader2Text( pElem.text() );
00284     }
00285 
00286     // Footer TODO (more details)
00287     QDomElement footerElem = KoDom::namedItemNS( chartElem, KoXmlNS::chart,
00288                          "footer" );
00289     if ( !footerElem.isNull() ) {
00290         loadingContext.styleStack().save();
00291         loadingContext.fillStyleStack( footerElem, KoXmlNS::chart, "style-name", "chart" );
00292         QFont font;
00293         QColor color;
00294         loadOasisFont( loadingContext, font, color );
00295         setHeaderFooterFont( KDChartParams::HdFtPosFooter, font, true, font.pointSize() );
00296         setHeaderFooterColor( KDChartParams::HdFtPosFooter, color );
00297         loadingContext.styleStack().restore();
00298 
00299     QDomElement  pElem = KoDom::namedItemNS( footerElem,
00300                          KoXmlNS::text, "p" );
00301     setFooterText( pElem.text() );
00302     }
00303 
00304     // TODO: Get legend settings
00305     QDomElement legendElem = KoDom::namedItemNS( chartElem, KoXmlNS::chart,
00306                          "legend" );
00307     if ( !legendElem.isNull() )
00308     {
00309         loadingContext.styleStack().save();
00310         loadingContext.fillStyleStack( legendElem, KoXmlNS::chart, "style-name", "chart" );
00311         QFont font;
00312         QColor color;
00313         loadOasisFont( loadingContext, font, color );
00314         //tz I didn't find that Oasis support seperate font/colors for the title and the rest of the legent
00315         setLegendFont( font, true );
00316         setLegendTitleFont( font, true );
00317         setLegendTextColor( color );
00318         setLegendTitleTextColor( color );
00319         loadingContext.styleStack().restore();
00320         QString lp;
00321         if ( legendElem.hasAttributeNS( KoXmlNS::chart, "legend-position" ) )
00322         {
00323             lp = legendElem.attributeNS( KoXmlNS::chart, "legend-position", QString::null );
00324         }
00325         QString lalign;
00326         if ( legendElem.hasAttributeNS( KoXmlNS::chart, "legend-align" ) )
00327         {
00328             lalign = legendElem.attributeNS( KoXmlNS::chart, "legend-align", QString::null );
00329         }
00330 
00331         LegendPosition lpos = NoLegend;
00332         int align = 1;
00333         if ( lalign == "start" )
00334         {
00335             align = 0;
00336         }
00337         else if ( lalign == "end" )
00338         {
00339             align = 2;
00340         }
00341 
00342         if ( lp == "start" )
00343         {
00344             lpos = LegendLeft;
00345             if ( align == 0 )
00346                 lpos = LegendTopLeftLeft;
00347             else if ( align == 2 )    
00348                 lpos = LegendBottomLeftLeft;
00349         }
00350         else if ( lp == "end" )
00351         {
00352             lpos = LegendRight;
00353             if ( align == 0 )
00354                 lpos = LegendTopRightRight;
00355             else if ( align == 2 )    
00356                 lpos = LegendBottomRightRight;
00357         }
00358         else if ( lp == "top" )
00359         {
00360             lpos = LegendTop;
00361             if ( align == 0 )
00362                 lpos = LegendTopLeftTop;
00363             else if ( align == 2 )    
00364                 lpos = LegendTopRightTop;
00365         }
00366         else if ( lp == "bottom" )
00367         {
00368             lpos = LegendBottom;
00369             if ( align == 0 )
00370                 lpos = LegendBottomLeftBottom;
00371             else if ( align == 2 )    
00372                 lpos = LegendBottomRightBottom;
00373         }
00374         else if ( lp == "top-start" )
00375         {
00376             lpos = LegendTopLeft;
00377         }
00378         else if ( lp == "bottom-start" )
00379         {
00380             lpos = LegendBottomLeft;
00381         }
00382         else if ( lp == "top-end" )
00383         {
00384             lpos = LegendTopRight;
00385         }
00386         else if ( lp == "bottom-end" )
00387         {
00388             lpos = LegendBottomRight;
00389         }
00390 
00391         setLegendPosition( lpos );
00392         //bodyWriter->addAttribute( "koffice:title", legendTitleText() );
00393         if ( legendElem.hasAttributeNS( KoXmlNS::koffice, "title" ) )
00394         {
00395             setLegendTitleText( legendElem.attributeNS( KoXmlNS::koffice, "title", QString::null ) );
00396         }
00397     }
00398     else
00399     {
00400         setLegendPosition( NoLegend );
00401     }
00402 
00403     // Get the plot-area.  This is where the action is.
00404     QDomElement  plotareaElem = KoDom::namedItemNS( chartElem,
00405                             KoXmlNS::chart, "plot-area" );
00406     if ( !plotareaElem.isNull() ) {
00407     return loadOasisPlotarea( plotareaElem, loadingContext, errorMessage );
00408     }
00409 
00410     return false;
00411 }
00412 
00413 
00414 bool KChartParams::loadOasisPlotarea( const QDomElement     &plotareaElem,
00415                       KoOasisLoadingContext &loadingContext,
00416                       QString               &errorMessage )
00417 {
00418     QString  tmp;
00419 
00420     //cerr << ">>> ==========================================================\n";
00421 
00422     // FIXME: attribute table:cell-range-address  - the cells in a spreadsheet
00423 
00424     // Get whether there is a label on the first row or column of the data.
00425     // This info is in the attribute chart:data-source-has-labels.
00426     //
00427     // NOTE: Only used in spreadsheets.
00428     tmp = plotareaElem.attributeNS( KoXmlNS::chart,
00429                     "data-source-has-labels", QString::null );
00430     m_firstRowAsLabel = false;
00431     m_firstColAsLabel = false;
00432     if ( tmp == "none" || tmp == "" )
00433     ; // NOTHING
00434     else if ( tmp == "row" )
00435     m_firstRowAsLabel = true;
00436     else if ( tmp == "column" )
00437     m_firstColAsLabel = true;
00438     else if ( tmp == "both" ) {
00439     m_firstRowAsLabel = true;
00440     m_firstColAsLabel = true;
00441     }
00442     else {
00443     errorMessage = "Unknown value for chart:data-source-has-labels:"
00444         + tmp;
00445     return false;
00446     }
00447 
00448     // ----------------------------------------------------------------
00449     // Now get the style and use it to get the contents.
00450     // This is hidden in the attribute chart:style-name.
00451     KoStyleStack          &styleStack = loadingContext.styleStack();
00452 
00453 
00454     tmp = plotareaElem.attributeNS( KoXmlNS::chart, "style-name",
00455                     QString::null );
00456     //kdDebug(35001) << "Style name for the plot area: " << tmp << endl;
00457     styleStack.save();
00458     styleStack.setTypeProperties( "chart" ); // load chart properties
00459     loadingContext.fillStyleStack( plotareaElem, KoXmlNS::chart, "style-name", "chart" );
00460 
00461     if ( styleStack.attributeNS( KoXmlNS::chart, "three-dimensional" ) == "true" ) {
00462     setThreeDBars( true );
00463     setThreeDLines( true );
00464     setThreeDPies( true );
00465     }
00466     else {
00467     setThreeDBars( false );
00468     setThreeDLines( false );
00469     setThreeDPies( false );
00470     }
00471 
00472     switch ( m_chartType ) {
00473     case NoType:
00474     break;
00475 
00476     case Bar:
00477     // Find out subtype
00478     tmp = styleStack.attributeNS( KoXmlNS::chart, "vertical" );
00479     // FIXME: Vertical is ignored. At least store it so we can
00480     //        save it again even if we don't support it.
00481 
00482     //kdDebug(35001) << "  ======>  Vertical: " << tmp << "  <======" << endl;
00483     // Set the bar chart subtype.
00484     if ( styleStack.attributeNS( KoXmlNS::chart, "stacked" ) == "true" )
00485         setBarChartSubType( BarStacked );
00486     else if ( styleStack.attributeNS( KoXmlNS::chart, "percentage" ) == "true" )
00487         setBarChartSubType( BarPercent );
00488     else
00489         setBarChartSubType( BarNormal );
00490 
00491     break;
00492 
00493     // chart:vertical      - true if vertical bars (only bar charts)
00494     // chart:stacked       - true for stacked bars
00495     // chart:percentage    - true for percentage  (mut. excl with stacked)
00496     // chart:connect-bars  - true if lines to connect bars should be drawn
00497     //                           only used for stacked and percentage bars.
00498     // FIXME: Support lines on bar charts.
00499     // chart:lines-used    - 0-n, number of lines on a bar chart. (def: 0)
00500 
00501     case Line:
00502     // Set the line chart subtype.
00503     if ( styleStack.attributeNS( KoXmlNS::chart, "stacked" ) == "true" )
00504         setLineChartSubType( LineStacked );
00505     else if ( styleStack.attributeNS( KoXmlNS::chart, "percentage" ) == "true" )
00506         setLineChartSubType( LinePercent );
00507     else
00508         setLineChartSubType( LineNormal );
00509 
00510     break;
00511 
00512     // FIXME: Why is this even there?  Seems like an unnecessary attr.
00513     // chart:lines       - true for line charts, false otherwise
00514 
00515     // chart:stacked     - true for stacked bars
00516     // chart:percentage  - true for percentage  (mut. excl with stacked)
00517 
00518     // chart:symbol-type - used with line charts, should be "automatic"
00519 
00520     case Area:
00521     // Set the area chart subtype.
00522     if ( styleStack.attributeNS( KoXmlNS::chart, "stacked" ) == "true" )
00523         setAreaChartSubType( AreaStacked );
00524     else if ( styleStack.attributeNS( KoXmlNS::chart, "percentage" ) == "true" )
00525         setAreaChartSubType( AreaPercent );
00526     else
00527         setAreaChartSubType( AreaNormal );
00528 
00529     break;
00530 
00531     // chart:stacked       - true for stacked bars
00532     // chart:percentage    - true for percentage  (mut. excl with stacked)
00533 
00534     case Pie:
00535     break;
00536 
00537     case HiLo:
00538     break;
00539 
00540     case Ring:
00541     break;
00542 
00543     case Polar:
00544     break;
00545 
00546     case BoxWhisker:
00547     break;
00548     }
00549     // TODO:
00550     // And get the info from the style.  Here is the contents:
00551 
00552 
00553     // TODO: These items are currently not used.  They should be at least
00554     //       be stored so that we can save them again.
00555     // chart:interpolation     - "cubic-spline" if using cubic splines
00556     // chart:splines           -
00557     // chart:spline-order      - "2" for cubic splines
00558     // chart:spline-resolution - how smooth (default: 20)
00559 
00560     // -- Used when chart:class == "stock:
00561     // chart:stock-updown-bars      - boolean
00562     // chart:stock-with-volume      - boolean
00563     // chart:japanese-candle-sticks - boolean
00564 
00565     // chart:series-source     - "row" or "columns
00566 
00567     // chart:data-label-number - "value" / "percentage" / "none" (def: none)
00568 
00569     // chart:data-label-text   - true if data hapoints have text labels
00570     // chart:data-label-symbol - true if data hapoints have legend symbol
00571     //                           (default: false for both)
00572 
00573     styleStack.restore();
00574 
00575     // ----------------------------------------------------------------
00576     // In the plot-area element there are two chart:axis elements
00577 
00578     QDomElement  xAxisElem;
00579     QDomElement  yAxisElem;
00580 
00581     QDomElement  axisElem;
00582     forEachElement( axisElem, plotareaElem ) {
00583 
00584     //cerr << "plotarea element: " << axisElem.tagName().latin1() << "\n";
00585     if ( axisElem.tagName() != "axis" )
00586         continue;
00587 
00588     tmp = axisElem.attributeNS( KoXmlNS::chart, "name",
00589                     QString::null);
00590     //kdDebug(35001) << "Got axis " << tmp << endl;
00591     //cerr << "Got axis " << tmp.latin1() << "\n";
00592     if ( tmp == "primary-x" )
00593         xAxisElem = axisElem;
00594     else if ( tmp == "primary-y" )
00595         yAxisElem = axisElem;
00596     else
00597         // Only supports two axes so far.
00598         continue;
00599     }
00600 
00601     // Load the axes.
00602     if ( !loadOasisAxis( xAxisElem, loadingContext, errorMessage,
00603              KDChartAxisParams::AxisPosBottom) )
00604     return false;
00605     if ( m_chartType != Pie
00606      && !loadOasisAxis( yAxisElem, loadingContext, errorMessage,
00607                 KDChartAxisParams::AxisPosLeft) )
00608     return false;
00609 
00610     // Attributes for the axes:
00611     // chart:name       - either "primary-x" or "primary-y"
00612 
00613 #if 0
00614     const QString fillColor = styleStack.attributeNS( KoXmlNS::draw,
00615                               "fill-color" );
00616     kdDebug() << "fillColor=" << fillColor << endl;
00617 #endif
00618 
00619     //cerr << "<<< ==========================================================\n";
00620 
00621     return true;
00622 }
00623 
00624 
00625 bool KChartParams::loadOasisAxis( const QDomElement      &axisElem,
00626                   KoOasisLoadingContext  &loadingContext,
00627                   QString                &errorMessage,
00628                   KDChartAxisParams::AxisPos  axisPos )
00629 {
00630     Q_UNUSED( errorMessage );
00631 
00632     QString        tmp;
00633     QDomElement    tmpElem;
00634     KoStyleStack  &styleStack = loadingContext.styleStack();
00635 
00636     // Get the axis to manipulate.
00637     // TODO
00638 
00639     // Get the axis title if any.
00640     QDomElement  titleElem = KoDom::namedItemNS( axisElem,
00641                          KoXmlNS::chart, "title" );
00642     if ( !titleElem.isNull() ) {
00643     tmpElem = KoDom::namedItemNS( titleElem, KoXmlNS::text, "p" );
00644     setAxisTitle( axisPos, tmpElem.text() );
00645     }
00646 
00647 
00648 
00649     //cerr << ">>> ----------------------------------------------------------\n";
00650     //cerr << "Loading axis " << axisElem.attributeNS( KoXmlNS::chart, "name",
00651     //                           QString::null).latin1()
00652     //   << "\n";
00653 
00654     tmp = axisElem.attributeNS( KoXmlNS::chart, "style-name", QString::null );
00655     //kdDebug(35001) << "Style name for the axis: " << tmp << endl;
00656     //cerr << "Style name for the axis: " << tmp.latin1() << "\n";
00657     styleStack.save();
00658     styleStack.setTypeProperties( "chart" ); // load chart properties
00659     loadingContext.fillStyleStack( axisElem, KoXmlNS::chart, "style-name", "chart" );
00660 
00661     // chart:class      - "category" / "value" / "domain" (domain for scatter)
00662     //    child: chart:categories
00663 
00664     // child:  chart:title   - Name of title if any.
00665     // child:  chart:grid
00666     //           attr: chart:class  - "major" / "minor"
00667 
00668     // chart:style-name - Associated style with the following info:
00669     // --------------------------------
00670     // chart:display-label          - true if an axis label should be shown.
00671 
00672     // chart:tick-marks-major-inner - true if display tickmarks at major
00673     // chart:tick-marks-major-outer   or minor intervals outside / inside
00674     // chart:tick-minor-major-inner   the chart area.
00675     // chart:tick-minor-major-outer
00676 
00677     // chart:logarithmic            - true if logarithmic scale
00678 
00679     // text:line-break              - true if categories can be broken
00680 
00681     // chart:text-overlap           - true if labels can overlap
00682 
00683     // chart:label-arrangement      - "side-by-side" / "stagger-even" /
00684     //                                "stagger-odd"  (def: side-by-side)
00685 
00686     // chart:visible                - true if labels + ticks should be shown.
00687 
00688     // children:
00689     // chart:
00690     // chart:
00691     // chart:
00692     // chart:
00693     // chart:
00694     styleStack.restore();
00695 
00696     //cerr << "<<< ----------------------------------------------------------\n";
00697     return true;
00698 }
00699 
00700 
00701 // ----------------------------------------------------------------
00702 
00703 
00704 void KChartParams::saveOasis( KoXmlWriter* bodyWriter, KoGenStyles& mainStyles ) const
00705 {
00706     bool knownType = false;
00707     for ( unsigned int i = 0 ; i < numOasisChartTypes ; ++i ) {
00708         if ( m_chartType == oasisChartTypes[i].chartType ) {
00709             bodyWriter->addAttribute( "chart:class", oasisChartTypes[i].oasisClass );
00710             knownType = true;
00711             break;
00712         }
00713     }
00714 
00715     if ( !knownType ) {
00716         kdError(32001) << "Unknown chart type in KChartParams::saveOasis, extend oasisChartTypes!" << endl;
00717     }
00718 
00719     bodyWriter->startElement( "chart:title" );
00720     QRect rect( headerFooterRect( KDChartParams::HdFtPosHeader ) );
00721     bodyWriter->addAttributePt( "svg:x", rect.x() );
00722     bodyWriter->addAttributePt( "svg:y", rect.y() );
00723     bodyWriter->addAttribute( "chart:style-name", saveOasisFont( mainStyles, header1Font(), headerFooterColor( KDChartParams::HdFtPosHeader ) ) );
00724     bodyWriter->startElement( "text:p" );
00725     bodyWriter->addTextNode( header1Text() );
00726     bodyWriter->endElement(); // text:p
00727     bodyWriter->endElement(); // chart:title
00728 
00729     QString subTitle( header2Text() );
00730     if ( !subTitle.isEmpty() ) {
00731 
00732         kdDebug(32001) << "header rect: " << headerFooterRect( KDChartParams::HdFtPosHeader2 ) << endl;
00733         QRect rect( headerFooterRect( KDChartParams::HdFtPosHeader2 ) );
00734         bodyWriter->startElement( "chart:subtitle" );
00735         bodyWriter->addAttributePt( "svg:x", rect.x() );
00736         bodyWriter->addAttributePt( "svg:y", rect.y() );
00737         bodyWriter->addAttribute( "chart:style-name", 
00738                   saveOasisFont( mainStyles, 
00739                          header2Font(), 
00740                          headerFooterColor( KDChartParams::HdFtPosHeader2 ) ) );
00741 
00742         bodyWriter->startElement( "text:p" );
00743         bodyWriter->addTextNode( subTitle );
00744         bodyWriter->endElement(); // text:p
00745         bodyWriter->endElement(); // chart:subtitle
00746     }
00747 
00748 
00749     QString footer( footerText() );
00750     if ( !footer.isEmpty() ) {
00751         QRect rect( headerFooterRect( KDChartParams::HdFtPosFooter ) );
00752         bodyWriter->startElement( "chart:footer" );
00753         bodyWriter->addAttributePt( "svg:x", rect.x() );
00754         bodyWriter->addAttributePt( "svg:y", rect.y() );
00755         bodyWriter->addAttribute( "chart:style-name",
00756                   saveOasisFont( mainStyles, 
00757                          footerFont(), 
00758                          headerFooterColor( KDChartParams::HdFtPosFooter ) ) );
00759 
00760         bodyWriter->startElement( "text:p" );
00761         bodyWriter->addTextNode( footer );
00762         bodyWriter->endElement(); // text:p
00763         bodyWriter->endElement(); // chart:footer
00764     }
00765 
00766     // TODO legend
00767     LegendPosition lpos = legendPosition();
00768     if ( lpos != NoLegend ) {
00769         bodyWriter->startElement( "chart:legend" );
00770         QString lp;
00771         QString lalign;
00772         switch ( lpos ) {
00773     case LegendTop: 
00774         lp = "top";
00775         lalign = "center";
00776         break;
00777     case LegendBottom:
00778         lp = "bottom";
00779         lalign = "center";
00780         break;
00781     case LegendLeft: 
00782         lp = "start";
00783         lalign = "center";
00784         break;
00785     case LegendRight:
00786         lp = "end";
00787         lalign = "center";
00788         break;
00789     case LegendTopLeft:
00790         lp = "top-start";
00791         break;
00792     case LegendTopLeftTop:
00793         lp = "top";
00794         lalign = "start";
00795         break;
00796     case LegendTopLeftLeft:
00797         lp = "start";
00798         lalign = "start";
00799         break;
00800     case LegendTopRight:
00801         lp = "top-end";
00802         break;
00803     case LegendTopRightTop:
00804         lp = "top";
00805         lalign = "end";
00806         break;
00807     case LegendTopRightRight:
00808         lp = "end";
00809         lalign = "start";
00810         break;
00811     case LegendBottomLeft:
00812         lp = "bottom-start";
00813         break;
00814     case LegendBottomLeftBottom:
00815         lp = "bottom";
00816         lalign = "start";
00817         break;
00818     case LegendBottomLeftLeft:
00819         lp = "start";
00820         lalign = "end";
00821         break;
00822     case LegendBottomRight:
00823         lp = "bottom-end";
00824         break;
00825     case LegendBottomRightBottom:
00826         lp = "bottom";
00827         lalign = "end";
00828         break;
00829     case LegendBottomRightRight:
00830         lp = "end";
00831         lalign = "end";
00832         break;
00833     default:
00834         lp = "end";
00835         lalign = "center";
00836         break;
00837         }
00838 
00839         bodyWriter->addAttribute( "chart:legend-position", lp );
00840         bodyWriter->addAttribute( "chart:legend-align", lalign );
00841         bodyWriter->addAttribute( "chart:style-name",
00842                   saveOasisFont( mainStyles, 
00843                          legendFont(), 
00844                          legendTextColor() ) );
00845         bodyWriter->addAttribute( "koffice:title", legendTitleText() );
00846         bodyWriter->endElement(); // chart:legend
00847     }
00848 
00849     bodyWriter->startElement( "chart:plot-area" );
00850     saveOasisPlotArea( bodyWriter, mainStyles );
00851     bodyWriter->endElement();
00852 
00853     // TODO...
00854 }
00855 
00856 
00857 void KChartParams::saveOasisPlotArea( KoXmlWriter* bodyWriter, KoGenStyles& mainStyles ) const
00858 {
00859     QString dataSourceHasLabels;
00860     if ( m_firstRowAsLabel )
00861         if ( m_firstColAsLabel )
00862             dataSourceHasLabels = "both";
00863         else
00864             dataSourceHasLabels = "row";
00865     else
00866         if ( m_firstColAsLabel )
00867             dataSourceHasLabels = "column";
00868         else
00869             dataSourceHasLabels = "none";
00870     bodyWriter->addAttribute( "chart:data-source-has-labels", dataSourceHasLabels );
00871 
00872     // Prepare the style for the plot area
00873     KoGenStyle plotAreaStyle( KoGenStyle::STYLE_AUTO, "chart" );
00874 
00875     switch ( m_chartType ) {
00876     case NoType:
00877     break;
00878 
00879     case Bar:
00880         switch( barChartSubType() ) {
00881         case BarStacked:
00882             plotAreaStyle.addProperty( "chart:stacked", "true" );
00883             break;
00884         case BarPercent:
00885             plotAreaStyle.addProperty( "chart:percentage", "true" );
00886             break;
00887         case BarNormal:
00888             break;
00889     case BarMultiRows:
00890         break;
00891         }
00892         plotAreaStyle.addProperty( "chart:vertical", "false" ); // #### always?
00893         plotAreaStyle.addProperty( "chart:lines-used", 0 ); // FIXME: for now
00894 
00895     if ( threeDBars() )
00896         plotAreaStyle.addProperty( "chart:three-dimensional", "true" );
00897 
00898     case Line:
00899         switch( lineChartSubType() ) {
00900         case LineStacked:
00901             plotAreaStyle.addProperty( "chart:stacked", "true" );
00902             break;
00903         case LinePercent:
00904             plotAreaStyle.addProperty( "chart:percentage", "true" );
00905             break;
00906         case LineNormal:
00907             break;
00908         }
00909         plotAreaStyle.addProperty( "chart:symbol-type", "automatic" );
00910 
00911     if ( threeDLines() )
00912         plotAreaStyle.addProperty( "chart:three-dimensional", "true" );
00913 
00914         break;
00915 
00916     case Area:
00917         switch( areaChartSubType() ) {
00918         case AreaStacked:
00919             plotAreaStyle.addProperty( "chart:stacked", "true" );
00920             break;
00921         case AreaPercent:
00922             plotAreaStyle.addProperty( "chart:percentage", "true" );
00923             break;
00924         case AreaNormal:
00925             break;
00926         }
00927         //plotAreaStyle.addProperty( "chart:lines-used", 0 ); // #### for now
00928 
00929         // TODO - very similar
00930 
00931     case Pie:
00932     if ( threeDPies() )
00933         plotAreaStyle.addProperty( "chart:three-dimensional", "true" );
00934 
00935     break;
00936 
00937     case HiLo:
00938     break;
00939 
00940     case Ring:
00941     break;
00942 
00943     case Polar:
00944     break;
00945 
00946     case BoxWhisker:
00947     break;
00948     }
00949 
00950     // Register the style, and get back its auto-generated name
00951     const QString styleName = mainStyles.lookup( plotAreaStyle, "ch" );
00952 
00953     bodyWriter->addAttribute( "chart:style-name", styleName );
00954 
00955     saveOasisAxis( bodyWriter, mainStyles, KDChartAxisParams::AxisPosBottom, "x" );
00956     saveOasisAxis( bodyWriter, mainStyles, KDChartAxisParams::AxisPosLeft, "y" );
00957 
00958     // TODO chart:series
00959     // TODO chart:wall
00960     // TODO chart:floor
00961 }
00962 
00963 
00964 void KChartParams::saveOasisAxis( KoXmlWriter* bodyWriter, 
00965                   KoGenStyles& mainStyles,
00966                                   KDChartAxisParams::AxisPos /*axisPos*/, 
00967                   const char* axisName ) const
00968 {
00969     bodyWriter->startElement( "chart:axis" );
00970 
00971     bodyWriter->addAttribute( "chart:dimension", axisName );
00972     bodyWriter->addAttribute( "chart:name", QCString( "primary-" ) + axisName );
00973 
00974     KoGenStyle axisStyle( KoGenStyle::STYLE_AUTO, "chart" );
00975 
00976     // TODO save axis style properties, like
00977     axisStyle.addProperty( "chart:display-label", "true" ); // ###
00978 
00979 
00980     const QString styleName = mainStyles.lookup( axisStyle, "ch" );
00981     bodyWriter->addAttribute( "chart:style-name", styleName );
00982 
00983     // TODO x axis has chart:categories, y axis has chart:grid ?
00984     // Maybe that part should be done by the caller of saveOasisAxis then
00985     // including the opening/closing of the chart:axis element...
00986 
00987     bodyWriter->endElement(); // chart:axis
00988 }
00989 
00990 
00991 QString KChartParams::saveOasisFont( KoGenStyles& mainStyles, const QFont& font, const QColor& color ) const
00992 {
00993     KoGenStyle::PropertyType tt = KoGenStyle::TextType;
00994     KoGenStyle autoStyle( KoGenStyle::STYLE_AUTO, "chart", 0 );
00995     autoStyle.addProperty( "fo:font-family", font.family(), tt );
00996     autoStyle.addPropertyPt( "fo:font-size", font.pointSize(), tt );
00997     autoStyle.addProperty( "fo:color", color.isValid() ? color.name() : "#000000", tt );
00998     int w = font.weight();
00999     autoStyle.addProperty( "fo:font-weight", w == 50 ? "normal" : w == 75 ? "bold" : QString::number( qRound(  w / 10 ) * 100 ), tt );
01000     autoStyle.addProperty( "fo:font-style", font.italic() ? "italic" : "normal", tt );
01001 
01002     return mainStyles.lookup( autoStyle, "ch", KoGenStyles::ForceNumbering );
01003 }
01004 
01005 
01006 }  //KChart namespace
01007 
KDE Home | KDE Accessibility Home | Description of Access Keys