You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1044 lines
33 KiB
1044 lines
33 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 2001,2002,2003,2004 Laurent Montel <montel@kde.org>
|
|
Copyright (C) 2006 Thorsten Zachmann <zachmann@kde.org>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
|
|
//#include <stdlib.h>
|
|
#include <iostream>
|
|
using std::cout;
|
|
using std::cerr;
|
|
|
|
|
|
#include <dcopobject.h>
|
|
#include <klocale.h>
|
|
#include <kdebug.h>
|
|
|
|
#include <KoXmlNS.h>
|
|
#include <KoXmlWriter.h>
|
|
#include <KoDom.h>
|
|
#include <KoOasisLoadingContext.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include "kdchart/KDChartParams.h"
|
|
#include "kdchart/KDChartAxisParams.h"
|
|
|
|
#include "kchart_params.h"
|
|
#include "kchart_part.h"
|
|
#include "KChartParamsIface.h"
|
|
|
|
|
|
namespace KChart
|
|
{
|
|
|
|
|
|
KChartParams::KChartParams( KChartPart *_part )
|
|
: KDChartParams(),
|
|
m_part( _part )
|
|
{
|
|
// Default values for subtypes.
|
|
m_firstRowAsLabel = false;
|
|
m_firstColAsLabel = false;
|
|
|
|
// Default values for OpenDocument extensions.
|
|
m_barNumLines = 0;
|
|
|
|
m_dcop = 0;
|
|
//dcopObject(); // build it
|
|
}
|
|
|
|
|
|
KChartParams::~KChartParams()
|
|
{
|
|
delete m_dcop;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
|
|
TQString KChartParams::chartTypeToString( ChartType _type) const
|
|
{
|
|
#if 0
|
|
if (_type == BarLines )
|
|
return "BarLines";
|
|
else
|
|
#endif
|
|
return KDChartParams::chartTypeToString( (KDChartParams::ChartType) _type );
|
|
}
|
|
|
|
|
|
KChartParams::ChartType
|
|
KChartParams::stringToChartType( const TQString& _string )
|
|
{
|
|
#if 0
|
|
if ( _string == "BarLines" )
|
|
return BarLines;
|
|
else
|
|
#endif
|
|
return (ChartType) KDChartParams::stringToChartType( _string );
|
|
}
|
|
|
|
|
|
void KChartParams::setFirstRowAsLabel( bool _val )
|
|
{
|
|
m_firstRowAsLabel = _val;
|
|
|
|
// The rest of this method is only applicable if the data is from
|
|
// an external source, e.g. from kspread.
|
|
if ( m_part->canChangeValue() )
|
|
return;
|
|
|
|
m_part->doSetData( *m_part->data(),
|
|
m_firstRowAsLabel, m_firstColAsLabel );
|
|
}
|
|
|
|
void KChartParams::setFirstColAsLabel( bool _val )
|
|
{
|
|
m_firstColAsLabel = _val;
|
|
|
|
// The rest of this method is only applicable if the data is from
|
|
// an external source, e.g. kspread.
|
|
if ( m_part->canChangeValue() )
|
|
return;
|
|
|
|
m_part->doSetData( *m_part->data(),
|
|
m_firstRowAsLabel, m_firstColAsLabel );
|
|
}
|
|
|
|
|
|
DCOPObject* KChartParams::dcopObject()
|
|
{
|
|
if ( !m_dcop )
|
|
m_dcop = new KChartParamsIface( this );
|
|
return m_dcop;
|
|
}
|
|
|
|
|
|
// ================================================================
|
|
// Loading and Saving
|
|
|
|
|
|
|
|
static const struct {
|
|
const char *oasisClass;
|
|
KChartParams::ChartType chartType;
|
|
} oasisChartTypes[] = {
|
|
{ "chart:bar", KChartParams::Bar },
|
|
{ "chart:line", KChartParams::Line },
|
|
{ "chart:area", KChartParams::Area },
|
|
{ "chart:circle", KChartParams::Pie },
|
|
//{ "chart:xxx", KChartParams::HiLo },
|
|
//{ "chart:stock", KChartParams::??? },
|
|
//{ "chart:add-in", KChartParams::??? },
|
|
//{ "chart:scatter",KChartParams::??? },
|
|
{ "chart:ring", KChartParams::Ring },
|
|
{ "chart:radar", KChartParams::Polar }
|
|
//{ "chart:xxx", KChartParams::BoxWhisker },
|
|
|
|
//{ "chart:xxx", KChartParams::BarLines },
|
|
// FIXME: More?
|
|
};
|
|
|
|
|
|
static const unsigned int numOasisChartTypes
|
|
= sizeof oasisChartTypes / sizeof *oasisChartTypes;
|
|
|
|
|
|
#if 0 // Example code!!
|
|
KoOasisLoadingContext loadingContext( this, oasisStyles, store );
|
|
KoStyleStack &styleStack = loadingContext.styleStack();
|
|
|
|
styleStack.save();
|
|
styleStack.setTypeProperties( "graphic" ); // load graphic-properties
|
|
loadingContext.fillStyleStack( chartElem, KoXmlNS::chart, "style-name" );
|
|
|
|
const TQString fillColor = styleStack.attributeNS( KoXmlNS::draw, "fill-color" );
|
|
kDebug() << "fillColor=" << fillColor << endl;
|
|
|
|
styleStack.restore();
|
|
#endif
|
|
|
|
|
|
// Load the data from an OpenDocument chart:chart element.
|
|
|
|
void KChartParams::loadOasisFont( KoOasisLoadingContext& context, TQFont& font, TQColor& color )
|
|
{
|
|
KoStyleStack& styleStack = context.styleStack();
|
|
styleStack.setTypeProperties( "text" ); // load all style attributes from "style:text-properties"
|
|
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "color" ) ) { // 3.10.3
|
|
color.setNamedColor( styleStack.attributeNS( KoXmlNS::fo, "color" ) ); // #rrggbb format
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-family" ) // 3.10.9
|
|
|| styleStack.hasAttributeNS( KoXmlNS::style, "font-name" ) ) { // 3.10.8
|
|
// Hmm, the remove "'" could break it's in the middle of the fontname...
|
|
TQString fontName = styleStack.attributeNS( KoXmlNS::fo, "font-family" ).remove( "'" );
|
|
if ( fontName.isEmpty() ) {
|
|
// ##### TODO. This is wrong. style:font-name refers to a font-decl entry.
|
|
// We have to look it up there, and retrieve _all_ font attributes from it, not just the name.
|
|
fontName = styleStack.attributeNS( KoXmlNS::style, "font-name" ).remove( "'" );
|
|
}
|
|
// 'Thorndale' is not known outside OpenOffice so we substitute it
|
|
// with 'Times New Roman' that looks nearly the same.
|
|
if ( fontName == "Thorndale" )
|
|
fontName = "Times New Roman";
|
|
|
|
fontName.remove( TQRegExp( "\\sCE$" ) ); // Arial CE -> Arial
|
|
font.setFamily( fontName );
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-size" ) ) { // 3.10.14
|
|
double pointSize = styleStack.fontSize();
|
|
font.setPointSizeFloat( pointSize );
|
|
kdDebug(35001) << "font size: " << pointSize << endl;
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-weight" ) ) { // 3.10.24
|
|
TQString fontWeight = styleStack.attributeNS( KoXmlNS::fo, "font-weight" );
|
|
int boldness;
|
|
if ( fontWeight == "normal" )
|
|
boldness = 50;
|
|
else if ( fontWeight == "bold" )
|
|
boldness = 75;
|
|
else
|
|
// XSL/CSS has 100,200,300...900. Not the same scale as TQt!
|
|
// See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight
|
|
boldness = fontWeight.toInt() / 10;
|
|
font.setWeight( boldness );
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-style" ) ) { // 3.10.19
|
|
if ( styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "italic" ||
|
|
styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "oblique" ) { // no difference in kotext
|
|
font.setItalic( true );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool KChartParams::loadOasis( const TQDomElement &chartElem,
|
|
KoOasisLoadingContext &loadingContext,
|
|
TQString &errorMessage,
|
|
KoStore */*store*/ )
|
|
{
|
|
const TQString chartClass = chartElem.attributeNS( KoXmlNS::chart,
|
|
"class", TQString() );
|
|
bool knownType = false;
|
|
|
|
// Find out what KChart charttype the OASIS charttype corresponds to.
|
|
for ( unsigned int i = 0 ; i < numOasisChartTypes ; ++i ) {
|
|
if ( chartClass == oasisChartTypes[i].oasisClass ) {
|
|
kdDebug(35001) << "found chart of type " << chartClass << endl;
|
|
//cerr << "found chart of type " << chartClass.latin1() << "\n";
|
|
|
|
setChartType( oasisChartTypes[i].chartType );
|
|
knownType = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we can't find out what charttype it is, we might as well end here.
|
|
if ( !knownType ) {
|
|
errorMessage = i18n( "Unknown chart type %1" ).tqarg( chartClass );
|
|
kdDebug(35001) << errorMessage << endl;
|
|
return false;
|
|
}
|
|
|
|
// Title TODO (more details, e.g. font, placement etc)
|
|
TQDomElement titleElem = KoDom::namedItemNS( chartElem,
|
|
KoXmlNS::chart, "title" );
|
|
if ( !titleElem.isNull() ) {
|
|
loadingContext.styleStack().save();
|
|
loadingContext.fillStyleStack( titleElem, KoXmlNS::chart, "style-name", "chart" );
|
|
TQFont font;
|
|
TQColor color;
|
|
loadOasisFont( loadingContext, font, color );
|
|
setHeaderFooterFont( KDChartParams::HdFtPosHeader, font, true, font.pointSize()*4 );
|
|
setHeaderFooterColor( KDChartParams::HdFtPosHeader, color );
|
|
loadingContext.styleStack().restore();
|
|
|
|
TQDomElement pElem = KoDom::namedItemNS( titleElem,
|
|
KoXmlNS::text, "p" );
|
|
setHeader1Text( pElem.text() );
|
|
}
|
|
|
|
// Subtitle TODO (more details)
|
|
TQDomElement subtitleElem = KoDom::namedItemNS( chartElem, KoXmlNS::chart,
|
|
"subtitle" );
|
|
if ( !subtitleElem.isNull() ) {
|
|
loadingContext.styleStack().save();
|
|
loadingContext.fillStyleStack( subtitleElem, KoXmlNS::chart, "style-name", "chart" );
|
|
TQFont font;
|
|
TQColor color;
|
|
loadOasisFont( loadingContext, font, color );
|
|
setHeaderFooterFont( KDChartParams::HdFtPosHeader2, font, true, font.pointSize()*4 );
|
|
setHeaderFooterColor( KDChartParams::HdFtPosHeader2, color );
|
|
loadingContext.styleStack().restore();
|
|
|
|
TQDomElement pElem = KoDom::namedItemNS( subtitleElem,
|
|
KoXmlNS::text, "p" );
|
|
setHeader2Text( pElem.text() );
|
|
}
|
|
|
|
// Footer TODO (more details)
|
|
TQDomElement footerElem = KoDom::namedItemNS( chartElem, KoXmlNS::chart,
|
|
"footer" );
|
|
if ( !footerElem.isNull() ) {
|
|
loadingContext.styleStack().save();
|
|
loadingContext.fillStyleStack( footerElem, KoXmlNS::chart, "style-name", "chart" );
|
|
TQFont font;
|
|
TQColor color;
|
|
loadOasisFont( loadingContext, font, color );
|
|
setHeaderFooterFont( KDChartParams::HdFtPosFooter, font, true, font.pointSize()*4 );
|
|
setHeaderFooterColor( KDChartParams::HdFtPosFooter, color );
|
|
loadingContext.styleStack().restore();
|
|
|
|
TQDomElement pElem = KoDom::namedItemNS( footerElem,
|
|
KoXmlNS::text, "p" );
|
|
setFooterText( pElem.text() );
|
|
}
|
|
|
|
// TODO: Get legend settings
|
|
TQDomElement legendElem = KoDom::namedItemNS( chartElem, KoXmlNS::chart,
|
|
"legend" );
|
|
if ( !legendElem.isNull() )
|
|
{
|
|
loadingContext.styleStack().save();
|
|
loadingContext.fillStyleStack( legendElem, KoXmlNS::chart, "style-name", "chart" );
|
|
TQFont font;
|
|
TQColor color;
|
|
loadOasisFont( loadingContext, font, color );
|
|
//tz I didn't find that Oasis support seperate font/colors for the title and the rest of the legent
|
|
setLegendFont( font, false );
|
|
setLegendFontRelSize( font.pointSize()*4 );
|
|
setLegendTitleFont( font, false);
|
|
setLegendTitleFontRelSize( font.pointSize()*4 );
|
|
setLegendTextColor( color );
|
|
setLegendTitleTextColor( color );
|
|
loadingContext.styleStack().restore();
|
|
TQString lp;
|
|
if ( legendElem.hasAttributeNS( KoXmlNS::chart, "legend-position" ) )
|
|
{
|
|
lp = legendElem.attributeNS( KoXmlNS::chart, "legend-position", TQString() );
|
|
}
|
|
TQString lalign;
|
|
if ( legendElem.hasAttributeNS( KoXmlNS::chart, "legend-align" ) )
|
|
{
|
|
lalign = legendElem.attributeNS( KoXmlNS::chart, "legend-align", TQString() );
|
|
}
|
|
|
|
LegendPosition lpos = NoLegend;
|
|
int align = 1;
|
|
if ( lalign == "start" )
|
|
{
|
|
align = 0;
|
|
}
|
|
else if ( lalign == "end" )
|
|
{
|
|
align = 2;
|
|
}
|
|
|
|
if ( lp == "start" )
|
|
{
|
|
lpos = LegendLeft;
|
|
if ( align == 0 )
|
|
lpos = LegendTopLeftLeft;
|
|
else if ( align == 2 )
|
|
lpos = LegendBottomLeftLeft;
|
|
}
|
|
else if ( lp == "end" )
|
|
{
|
|
lpos = LegendRight;
|
|
if ( align == 0 )
|
|
lpos = LegendTopRightRight;
|
|
else if ( align == 2 )
|
|
lpos = LegendBottomRightRight;
|
|
}
|
|
else if ( lp == "top" )
|
|
{
|
|
lpos = LegendTop;
|
|
if ( align == 0 )
|
|
lpos = LegendTopLeftTop;
|
|
else if ( align == 2 )
|
|
lpos = LegendTopRightTop;
|
|
}
|
|
else if ( lp == "bottom" )
|
|
{
|
|
lpos = LegendBottom;
|
|
if ( align == 0 )
|
|
lpos = LegendBottomLeftBottom;
|
|
else if ( align == 2 )
|
|
lpos = LegendBottomRightBottom;
|
|
}
|
|
else if ( lp == "top-start" )
|
|
{
|
|
lpos = LegendTopLeft;
|
|
}
|
|
else if ( lp == "bottom-start" )
|
|
{
|
|
lpos = LegendBottomLeft;
|
|
}
|
|
else if ( lp == "top-end" )
|
|
{
|
|
lpos = LegendTopRight;
|
|
}
|
|
else if ( lp == "bottom-end" )
|
|
{
|
|
lpos = LegendBottomRight;
|
|
}
|
|
|
|
setLegendPosition( lpos );
|
|
//bodyWriter->addAttribute( "koffice:title", legendTitleText() );
|
|
if ( legendElem.hasAttributeNS( KoXmlNS::koffice, "title" ) )
|
|
{
|
|
setLegendTitleText( legendElem.attributeNS( KoXmlNS::koffice, "title", TQString() ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setLegendPosition( NoLegend );
|
|
}
|
|
|
|
// Get the plot-area. This is where the action is.
|
|
TQDomElement plotareaElem = KoDom::namedItemNS( chartElem,
|
|
KoXmlNS::chart, "plot-area" );
|
|
if ( !plotareaElem.isNull() ) {
|
|
return loadOasisPlotarea( plotareaElem, loadingContext, errorMessage );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool KChartParams::loadOasisPlotarea( const TQDomElement &plotareaElem,
|
|
KoOasisLoadingContext &loadingContext,
|
|
TQString &errorMessage )
|
|
{
|
|
TQString tmp;
|
|
|
|
//cerr << ">>> ==========================================================\n";
|
|
|
|
// FIXME: attribute table:cell-range-address - the cells in a spreadsheet
|
|
|
|
// Get whether there is a label on the first row or column of the data.
|
|
// This info is in the attribute chart:data-source-has-labels.
|
|
//
|
|
// NOTE: Only used in spreadsheets.
|
|
tmp = plotareaElem.attributeNS( KoXmlNS::chart,
|
|
"data-source-has-labels", TQString() );
|
|
m_firstRowAsLabel = false;
|
|
m_firstColAsLabel = false;
|
|
if ( tmp == "none" || tmp == "" )
|
|
; // NOTHING
|
|
else if ( tmp == "row" )
|
|
m_firstRowAsLabel = true;
|
|
else if ( tmp == "column" )
|
|
m_firstColAsLabel = true;
|
|
else if ( tmp == "both" ) {
|
|
m_firstRowAsLabel = true;
|
|
m_firstColAsLabel = true;
|
|
}
|
|
else {
|
|
errorMessage = "Unknown value for chart:data-source-has-labels:"
|
|
+ tmp;
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Now get the style and use it to get the contents.
|
|
// This is hidden in the attribute chart:style-name.
|
|
KoStyleStack &styleStack = loadingContext.styleStack();
|
|
|
|
|
|
tmp = plotareaElem.attributeNS( KoXmlNS::chart, "style-name",
|
|
TQString() );
|
|
//kdDebug(35001) << "Style name for the plot area: " << tmp << endl;
|
|
styleStack.save();
|
|
styleStack.setTypeProperties( "chart" ); // load chart properties
|
|
loadingContext.fillStyleStack( plotareaElem, KoXmlNS::chart, "style-name", "chart" );
|
|
|
|
if ( styleStack.attributeNS( KoXmlNS::chart, "three-dimensional" ) == "true" ) {
|
|
setThreeDBars( true );
|
|
setThreeDLines( true );
|
|
setThreeDPies( true );
|
|
}
|
|
else {
|
|
setThreeDBars( false );
|
|
setThreeDLines( false );
|
|
setThreeDPies( false );
|
|
}
|
|
|
|
switch ( m_chartType ) {
|
|
case NoType:
|
|
break;
|
|
|
|
case Bar:
|
|
// Find out subtype
|
|
tmp = styleStack.attributeNS( KoXmlNS::chart, "vertical" );
|
|
// FIXME:Qt::Vertical is ignored. At least store it so we can
|
|
// save it again even if we don't support it.
|
|
|
|
//kdDebug(35001) << " ======> Qt::Vertical: " << tmp << " <======" << endl;
|
|
// Set the bar chart subtype.
|
|
if ( styleStack.attributeNS( KoXmlNS::chart, "stacked" ) == "true" )
|
|
setBarChartSubType( BarStacked );
|
|
else if ( styleStack.attributeNS( KoXmlNS::chart, "percentage" ) == "true" )
|
|
setBarChartSubType( BarPercent );
|
|
else
|
|
setBarChartSubType( BarNormal );
|
|
|
|
break;
|
|
|
|
// chart:vertical - true if vertical bars (only bar charts)
|
|
// chart:stacked - true for stacked bars
|
|
// chart:percentage - true for percentage (mut. excl with stacked)
|
|
// chart:connect-bars - true if lines to connect bars should be drawn
|
|
// only used for stacked and percentage bars.
|
|
// FIXME: Support lines on bar charts.
|
|
// chart:lines-used - 0-n, number of lines on a bar chart. (def: 0)
|
|
|
|
case Line:
|
|
// Set the line chart subtype.
|
|
if ( styleStack.attributeNS( KoXmlNS::chart, "stacked" ) == "true" )
|
|
setLineChartSubType( LineStacked );
|
|
else if ( styleStack.attributeNS( KoXmlNS::chart, "percentage" ) == "true" )
|
|
setLineChartSubType( LinePercent );
|
|
else
|
|
setLineChartSubType( LineNormal );
|
|
|
|
break;
|
|
|
|
// FIXME: Why is this even there? Seems like an unnecessary attr.
|
|
// chart:lines - true for line charts, false otherwise
|
|
|
|
// chart:stacked - true for stacked bars
|
|
// chart:percentage - true for percentage (mut. excl with stacked)
|
|
|
|
// chart:symbol-type - used with line charts, should be "automatic"
|
|
|
|
case Area:
|
|
// Set the area chart subtype.
|
|
if ( styleStack.attributeNS( KoXmlNS::chart, "stacked" ) == "true" )
|
|
setAreaChartSubType( AreaStacked );
|
|
else if ( styleStack.attributeNS( KoXmlNS::chart, "percentage" ) == "true" )
|
|
setAreaChartSubType( AreaPercent );
|
|
else
|
|
setAreaChartSubType( AreaNormal );
|
|
|
|
break;
|
|
|
|
// chart:stacked - true for stacked bars
|
|
// chart:percentage - true for percentage (mut. excl with stacked)
|
|
|
|
case Pie:
|
|
break;
|
|
|
|
case HiLo:
|
|
break;
|
|
|
|
case Ring:
|
|
break;
|
|
|
|
case Polar:
|
|
break;
|
|
|
|
case BoxWhisker:
|
|
break;
|
|
}
|
|
// TODO:
|
|
// And get the info from the style. Here is the contents:
|
|
|
|
|
|
// TODO: These items are currently not used. They should be at least
|
|
// be stored so that we can save them again.
|
|
// chart:interpolation - "cubic-spline" if using cubic splines
|
|
// chart:splines -
|
|
// chart:spline-order - "2" for cubic splines
|
|
// chart:spline-resolution - how smooth (default: 20)
|
|
|
|
// -- Used when chart:class == "stock:
|
|
// chart:stock-updown-bars - boolean
|
|
// chart:stock-with-volume - boolean
|
|
// chart:japanese-candle-sticks - boolean
|
|
|
|
// chart:series-source - "rows" or "columns"
|
|
// "columns" is the default
|
|
if ( styleStack.attributeNS( KoXmlNS::chart, "series-source" ) == "rows" ) {
|
|
setDataDirection( DataRows );
|
|
}
|
|
|
|
// chart:data-label-number - "value" / "percentage" / "none" (def: none)
|
|
|
|
// chart:data-label-text - true if data hapoints have text labels
|
|
// chart:data-label-symbol - true if data hapoints have legend symbol
|
|
// (default: false for both)
|
|
|
|
styleStack.restore();
|
|
|
|
// ----------------------------------------------------------------
|
|
// In the plot-area element there are two chart:axis elements
|
|
|
|
TQDomElement xAxisElem;
|
|
TQDomElement yAxisElem;
|
|
|
|
TQDomElement axisElem;
|
|
forEachElement( axisElem, plotareaElem ) {
|
|
|
|
// If this element is not an axis, then continue
|
|
if ( axisElem.tagName() != "axis" )
|
|
continue;
|
|
|
|
tmp = axisElem.attributeNS( KoXmlNS::chart, "name",
|
|
TQString());
|
|
//kdDebug(35001) << "Got axis " << tmp << endl;
|
|
//cerr << "Got axis " << tmp.latin1() << "\n";
|
|
if ( tmp == "primary-x" )
|
|
xAxisElem = axisElem;
|
|
else if ( tmp == "primary-y" )
|
|
yAxisElem = axisElem;
|
|
else
|
|
// Only supports two axes so far.
|
|
continue;
|
|
}
|
|
|
|
// Load the axes. Pie charts use only the y axis.
|
|
if ( m_chartType != Pie
|
|
&& !loadOasisAxis( xAxisElem, loadingContext, errorMessage,
|
|
KDChartAxisParams::AxisPosBottom) )
|
|
return false;
|
|
if ( !loadOasisAxis( yAxisElem, loadingContext, errorMessage,
|
|
KDChartAxisParams::AxisPosLeft) )
|
|
return false;
|
|
|
|
// Attributes for the axes:
|
|
// chart:name - either "primary-x" or "primary-y"
|
|
|
|
#if 0
|
|
const TQString fillColor = styleStack.attributeNS( KoXmlNS::draw,
|
|
"fill-color" );
|
|
kdDebug() << "fillColor=" << fillColor << endl;
|
|
#endif
|
|
|
|
//cerr << "<<< ==========================================================\n";
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool KChartParams::loadOasisAxis( const TQDomElement &axisElem,
|
|
KoOasisLoadingContext &loadingContext,
|
|
TQString &errorMessage,
|
|
KDChartAxisParams::AxisPos axisPos )
|
|
{
|
|
Q_UNUSED( errorMessage );
|
|
|
|
TQString tmp;
|
|
TQDomElement tmpElem;
|
|
KoStyleStack &styleStack = loadingContext.styleStack();
|
|
|
|
// Get the axis to manipulate.
|
|
// TODO
|
|
|
|
// Get the axis title (== axis label) if any.
|
|
TQDomElement titleElem = KoDom::namedItemNS( axisElem,
|
|
KoXmlNS::chart, "title" );
|
|
if ( !titleElem.isNull() ) {
|
|
tmpElem = KoDom::namedItemNS( titleElem, KoXmlNS::text, "p" );
|
|
setAxisTitle( axisPos, tmpElem.text() );
|
|
}
|
|
|
|
|
|
|
|
//cerr << ">>> ----------------------------------------------------------\n";
|
|
//cerr << "Loading axis " << axisElem.attributeNS( KoXmlNS::chart, "name",
|
|
// TQString()).latin1()
|
|
// << "\n";
|
|
|
|
tmp = axisElem.attributeNS( KoXmlNS::chart, "style-name", TQString() );
|
|
//kdDebug(35001) << "Style name for the axis: " << tmp << endl;
|
|
//cerr << "Style name for the axis: " << tmp.latin1() << "\n";
|
|
styleStack.save();
|
|
styleStack.setTypeProperties( "chart" ); // load chart properties
|
|
loadingContext.fillStyleStack( axisElem, KoXmlNS::chart, "style-name", "chart" );
|
|
|
|
// chart:class - "category" / "value" / "domain" (domain for scatter)
|
|
// child: chart:categories
|
|
|
|
// child: chart:title - Name of title if any.
|
|
// child: chart:grid
|
|
// attr: chart:class - "major" / "minor"
|
|
|
|
// chart:style-name - Associated style with the following info:
|
|
// --------------------------------
|
|
// chart:display-label - true if an axis label should be shown.
|
|
|
|
// chart:tick-marks-major-inner - true if display tickmarks at major
|
|
// chart:tick-marks-major-outer or minor intervals outside / inside
|
|
// chart:tick-minor-major-inner the chart area.
|
|
// chart:tick-minor-major-outer
|
|
|
|
// chart:logarithmic - true if logarithmic scale
|
|
|
|
// text:line-break - true if categories can be broken
|
|
|
|
// chart:text-overlap - true if labels can overlap
|
|
|
|
// chart:label-arrangement - "side-by-side" / "stagger-even" /
|
|
// "stagger-odd" (def: side-by-side)
|
|
|
|
// chart:visible - true if labels + ticks should be shown.
|
|
|
|
// tqchildren:
|
|
// chart:
|
|
// chart:
|
|
// chart:
|
|
// chart:
|
|
// chart:
|
|
styleStack.restore();
|
|
|
|
//cerr << "<<< ----------------------------------------------------------\n";
|
|
return true;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
|
|
void KChartParams::saveOasis( KoXmlWriter* bodyWriter, KoGenStyles& mainStyles ) const
|
|
{
|
|
bool knownType = false;
|
|
for ( unsigned int i = 0 ; i < numOasisChartTypes ; ++i ) {
|
|
if ( m_chartType == oasisChartTypes[i].chartType ) {
|
|
bodyWriter->addAttribute( "chart:class", oasisChartTypes[i].oasisClass );
|
|
knownType = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !knownType ) {
|
|
kdError(32001) << "Unknown chart type in KChartParams::saveOasis, extend oasisChartTypes!" << endl;
|
|
}
|
|
|
|
bodyWriter->startElement( "chart:title" );
|
|
TQRect rect( headerFooterRect( KDChartParams::HdFtPosHeader ) );
|
|
bodyWriter->addAttributePt( "svg:x", rect.x() );
|
|
bodyWriter->addAttributePt( "svg:y", rect.y() );
|
|
bodyWriter->addAttribute( "chart:style-name", saveOasisFont( mainStyles, header1Font(), headerFooterColor( KDChartParams::HdFtPosHeader ) ) );
|
|
bodyWriter->startElement( "text:p" );
|
|
bodyWriter->addTextNode( header1Text() );
|
|
bodyWriter->endElement(); // text:p
|
|
bodyWriter->endElement(); // chart:title
|
|
|
|
TQString subTitle( header2Text() );
|
|
if ( !subTitle.isEmpty() ) {
|
|
|
|
kdDebug(32001) << "header rect: " << headerFooterRect( KDChartParams::HdFtPosHeader2 ) << endl;
|
|
TQRect rect( headerFooterRect( KDChartParams::HdFtPosHeader2 ) );
|
|
bodyWriter->startElement( "chart:subtitle" );
|
|
bodyWriter->addAttributePt( "svg:x", rect.x() );
|
|
bodyWriter->addAttributePt( "svg:y", rect.y() );
|
|
bodyWriter->addAttribute( "chart:style-name",
|
|
saveOasisFont( mainStyles,
|
|
header2Font(),
|
|
headerFooterColor( KDChartParams::HdFtPosHeader2 ) ) );
|
|
|
|
bodyWriter->startElement( "text:p" );
|
|
bodyWriter->addTextNode( subTitle );
|
|
bodyWriter->endElement(); // text:p
|
|
bodyWriter->endElement(); // chart:subtitle
|
|
}
|
|
|
|
|
|
TQString footer( footerText() );
|
|
if ( !footer.isEmpty() ) {
|
|
TQRect rect( headerFooterRect( KDChartParams::HdFtPosFooter ) );
|
|
bodyWriter->startElement( "chart:footer" );
|
|
bodyWriter->addAttributePt( "svg:x", rect.x() );
|
|
bodyWriter->addAttributePt( "svg:y", rect.y() );
|
|
bodyWriter->addAttribute( "chart:style-name",
|
|
saveOasisFont( mainStyles,
|
|
footerFont(),
|
|
headerFooterColor( KDChartParams::HdFtPosFooter ) ) );
|
|
|
|
bodyWriter->startElement( "text:p" );
|
|
bodyWriter->addTextNode( footer );
|
|
bodyWriter->endElement(); // text:p
|
|
bodyWriter->endElement(); // chart:footer
|
|
}
|
|
|
|
// TODO legend
|
|
LegendPosition lpos = legendPosition();
|
|
if ( lpos != NoLegend ) {
|
|
bodyWriter->startElement( "chart:legend" );
|
|
TQString lp;
|
|
TQString lalign;
|
|
switch ( lpos ) {
|
|
case LegendTop:
|
|
lp = "top";
|
|
lalign = "center";
|
|
break;
|
|
case LegendBottom:
|
|
lp = "bottom";
|
|
lalign = "center";
|
|
break;
|
|
case LegendLeft:
|
|
lp = "start";
|
|
lalign = "center";
|
|
break;
|
|
case LegendRight:
|
|
lp = "end";
|
|
lalign = "center";
|
|
break;
|
|
case LegendTopLeft:
|
|
lp = "top-start";
|
|
break;
|
|
case LegendTopLeftTop:
|
|
lp = "top";
|
|
lalign = "start";
|
|
break;
|
|
case LegendTopLeftLeft:
|
|
lp = "start";
|
|
lalign = "start";
|
|
break;
|
|
case LegendTopRight:
|
|
lp = "top-end";
|
|
break;
|
|
case LegendTopRightTop:
|
|
lp = "top";
|
|
lalign = "end";
|
|
break;
|
|
case LegendTopRightRight:
|
|
lp = "end";
|
|
lalign = "start";
|
|
break;
|
|
case LegendBottomLeft:
|
|
lp = "bottom-start";
|
|
break;
|
|
case LegendBottomLeftBottom:
|
|
lp = "bottom";
|
|
lalign = "start";
|
|
break;
|
|
case LegendBottomLeftLeft:
|
|
lp = "start";
|
|
lalign = "end";
|
|
break;
|
|
case LegendBottomRight:
|
|
lp = "bottom-end";
|
|
break;
|
|
case LegendBottomRightBottom:
|
|
lp = "bottom";
|
|
lalign = "end";
|
|
break;
|
|
case LegendBottomRightRight:
|
|
lp = "end";
|
|
lalign = "end";
|
|
break;
|
|
default:
|
|
lp = "end";
|
|
lalign = "center";
|
|
break;
|
|
}
|
|
|
|
bodyWriter->addAttribute( "chart:legend-position", lp );
|
|
bodyWriter->addAttribute( "chart:legend-align", lalign );
|
|
bodyWriter->addAttribute( "chart:style-name",
|
|
saveOasisFont( mainStyles,
|
|
legendFont(),
|
|
legendTextColor() ) );
|
|
bodyWriter->addAttribute( "koffice:title", legendTitleText() );
|
|
bodyWriter->endElement(); // chart:legend
|
|
}
|
|
|
|
bodyWriter->startElement( "chart:plot-area" );
|
|
saveOasisPlotArea( bodyWriter, mainStyles );
|
|
bodyWriter->endElement();
|
|
|
|
// TODO...
|
|
}
|
|
|
|
|
|
void KChartParams::saveOasisPlotArea( KoXmlWriter* bodyWriter, KoGenStyles& mainStyles ) const
|
|
{
|
|
TQString dataSourceHasLabels;
|
|
if ( m_firstRowAsLabel )
|
|
if ( m_firstColAsLabel )
|
|
dataSourceHasLabels = "both";
|
|
else
|
|
dataSourceHasLabels = "row";
|
|
else
|
|
if ( m_firstColAsLabel )
|
|
dataSourceHasLabels = "column";
|
|
else
|
|
dataSourceHasLabels = "none";
|
|
bodyWriter->addAttribute( "chart:data-source-has-labels", dataSourceHasLabels );
|
|
|
|
// Prepare the style for the plot area
|
|
KoGenStyle plotAreaStyle( KoGenStyle::STYLE_AUTO, "chart" );
|
|
|
|
switch ( m_chartType ) {
|
|
case NoType:
|
|
break;
|
|
|
|
case Bar:
|
|
switch( barChartSubType() ) {
|
|
case BarStacked:
|
|
plotAreaStyle.addProperty( "chart:stacked", "true" );
|
|
break;
|
|
case BarPercent:
|
|
plotAreaStyle.addProperty( "chart:percentage", "true" );
|
|
break;
|
|
case BarNormal:
|
|
break;
|
|
case BarMultiRows:
|
|
break;
|
|
}
|
|
plotAreaStyle.addProperty( "chart:vertical", "false" ); // #### always?
|
|
plotAreaStyle.addProperty( "chart:lines-used", 0 ); // FIXME: for now
|
|
|
|
if ( threeDBars() )
|
|
plotAreaStyle.addProperty( "chart:three-dimensional", "true" );
|
|
|
|
case Line:
|
|
switch( lineChartSubType() ) {
|
|
case LineStacked:
|
|
plotAreaStyle.addProperty( "chart:stacked", "true" );
|
|
break;
|
|
case LinePercent:
|
|
plotAreaStyle.addProperty( "chart:percentage", "true" );
|
|
break;
|
|
case LineNormal:
|
|
break;
|
|
}
|
|
plotAreaStyle.addProperty( "chart:symbol-type", "automatic" );
|
|
|
|
if ( threeDLines() )
|
|
plotAreaStyle.addProperty( "chart:three-dimensional", "true" );
|
|
|
|
break;
|
|
|
|
case Area:
|
|
switch( areaChartSubType() ) {
|
|
case AreaStacked:
|
|
plotAreaStyle.addProperty( "chart:stacked", "true" );
|
|
break;
|
|
case AreaPercent:
|
|
plotAreaStyle.addProperty( "chart:percentage", "true" );
|
|
break;
|
|
case AreaNormal:
|
|
break;
|
|
}
|
|
//plotAreaStyle.addProperty( "chart:lines-used", 0 ); // #### for now
|
|
|
|
// TODO - very similar
|
|
|
|
case Pie:
|
|
if ( threeDPies() )
|
|
plotAreaStyle.addProperty( "chart:three-dimensional", "true" );
|
|
|
|
break;
|
|
|
|
case HiLo:
|
|
break;
|
|
|
|
case Ring:
|
|
break;
|
|
|
|
case Polar:
|
|
break;
|
|
|
|
case BoxWhisker:
|
|
break;
|
|
}
|
|
|
|
// chart:series-source
|
|
plotAreaStyle.addProperty( "chart:series-source",
|
|
( dataDirection() == DataRows ) ? "rows" : "columns" );
|
|
|
|
// Register the style, and get back its auto-generated name
|
|
const TQString styleName = mainStyles.lookup( plotAreaStyle, "ch" );
|
|
|
|
bodyWriter->addAttribute( "chart:style-name", styleName );
|
|
|
|
saveOasisAxis( bodyWriter, mainStyles, KDChartAxisParams::AxisPosBottom, "x" );
|
|
saveOasisAxis( bodyWriter, mainStyles, KDChartAxisParams::AxisPosLeft, "y" );
|
|
|
|
// TODO chart:series
|
|
// TODO chart:wall
|
|
// TODO chart:floor
|
|
}
|
|
|
|
|
|
void KChartParams::saveOasisAxis( KoXmlWriter* bodyWriter,
|
|
KoGenStyles& mainStyles,
|
|
KDChartAxisParams::AxisPos axisPos,
|
|
const char* axisName ) const
|
|
{
|
|
bodyWriter->startElement( "chart:axis" );
|
|
|
|
bodyWriter->addAttribute( "chart:dimension", axisName );
|
|
bodyWriter->addAttribute( "chart:name", TQCString( "primary-" ) + axisName );
|
|
|
|
KoGenStyle axisStyle( KoGenStyle::STYLE_AUTO, "chart" );
|
|
|
|
// TODO: Save axis style properties, like
|
|
axisStyle.addProperty( "chart:display-label", "true" ); // ###
|
|
|
|
|
|
const TQString styleName = mainStyles.lookup( axisStyle, "ch" );
|
|
bodyWriter->addAttribute( "chart:style-name", styleName );
|
|
|
|
// Write axis titles if any.
|
|
TQString tmpStr = axisTitle( axisPos );
|
|
if ( tmpStr != "" ) {
|
|
bodyWriter->startElement( "chart:title" );
|
|
// TODO: Save style, svg:x, svg:y
|
|
|
|
// Write the text in the axis title.
|
|
bodyWriter->startElement( "text:p" );
|
|
bodyWriter->addTextNode( tmpStr
|
|
.remove( TQRegExp( "^<qt><center>" ) )
|
|
.remove( TQRegExp( "</center></qt>$" ) ) );
|
|
bodyWriter->endElement(); // text:p
|
|
|
|
bodyWriter->endElement(); // chart:title
|
|
}
|
|
|
|
// TODO x axis has chart:categories, y axis has chart:grid ?
|
|
// Maybe that part should be done by the caller of saveOasisAxis then
|
|
// including the opening/closing of the chart:axis element...
|
|
|
|
bodyWriter->endElement(); // chart:axis
|
|
}
|
|
|
|
|
|
TQString KChartParams::saveOasisFont( KoGenStyles& mainStyles, const TQFont& font, const TQColor& color ) const
|
|
{
|
|
KoGenStyle::PropertyType tt = KoGenStyle::TextType;
|
|
KoGenStyle autoStyle( KoGenStyle::STYLE_AUTO, "chart", 0 );
|
|
autoStyle.addProperty( "fo:font-family", font.family(), tt );
|
|
autoStyle.addPropertyPt( "fo:font-size", font.pointSize(), tt );
|
|
autoStyle.addProperty( "fo:color", color.isValid() ? color.name() : "#000000", tt );
|
|
int w = font.weight();
|
|
autoStyle.addProperty( "fo:font-weight", w == 50 ? "normal" : w == 75 ? "bold" : TQString::number( tqRound( w / 10 ) * 100 ), tt );
|
|
autoStyle.addProperty( "fo:font-style", font.italic() ? "italic" : "normal", tt );
|
|
|
|
return mainStyles.lookup( autoStyle, "ch", KoGenStyles::ForceNumbering );
|
|
}
|
|
|
|
|
|
} //KChart namespace
|
|
|