/**
 *
 * Kalle Dalheimer <kalle@kde.org>
 */

#include <float.h> // For basic data types characteristics.

// For debugging
#include <iostream>
using std::cout;
using std::cerr;

#include "kchart_part.h"
#include "kchart_view.h"
#include "kchart_factory.h"
#include "kchartWizard.h"
#include "kchart_params.h"
#include "kdchart/KDChart.h"
#include "kdchart/KDChartTable.h"

#include <KoTemplateChooseDia.h>
#include <KoDom.h>
#include <KoXmlNS.h>
#include <KoXmlWriter.h>
#include <KoOasisStore.h>
#include <KoOasisLoadingContext.h>

#include <kstandarddirs.h>
#include <kglobal.h>
#include <kdebug.h>

#include <qdom.h>
#include <qtextstream.h>
#include <qbuffer.h>
#include <qpainter.h>

using namespace std;

// Some hardcoded data for a chart

/* ----- set some data ----- */
// float   a[6]  = { 0.5, 0.09, 0.6, 0.85, 0.0, 0.90 },
// b[6]  = { 1.9, 1.3,  0.6, 0.75, 0.1, -2.0 };
/* ----- X labels ----- */
// char    *t[6] = { "Chicago", "New York", "L.A.", "Atlanta", "Paris, MD\n(USA) ", "London" };
/* ----- data set colors (RGB) ----- */
// QColor   sc[2]    = { QColor( 255, 128, 128 ), QColor( 128, 128, 255 ) };


namespace KChart
{

KChartPart::KChartPart( QWidget *parentWidget, const char *widgetName,
			QObject* parent, const char* name,
			bool singleViewMode )
  : KoChart::Part( parentWidget, widgetName, parent, name, singleViewMode ),
    m_params( 0 ),
    m_parentWidget( parentWidget ),
    m_rowLabels(), m_colLabels()
{
    kdDebug(35001) << "Constructor started!" << endl;

    setInstance( KChartFactory::global(), false );
    setTemplateType( "kchart_template" );

    // Init some members that need it.
    {
	// Create the chart parameters and let the default be a bar chart
	// with 3D looks.
	m_params = new KChartParams( this );
	m_params->setChartType( KChartParams::Bar );
	m_params->setBarChartSubType( KChartParams::BarNormal );
	m_params->setThreeDBars( true );

        //Changed this to use columns rather than rows by default
        //because I believe that this is the more common format for
        //entering data (you can see this looking at the fact that
        //most spreadsheet packages allow far more rows than columns)
        //-- Robert Knight

	// Handle data in columns by default
	m_params->setDataDirection( KChartParams::DataColumns );
    }

    (void)new WizardExt( this );
    m_bCanChangeValue = true;

    // Display parameters
    m_displayData = m_currentData;

    // Set the size to minimal.
    initEmpty();
}


KChartPart::~KChartPart()
{
    //kdDebug(35001) << "Part is going to be destroyed now!!!" << endl;
    delete m_params;
}


// Reimplement KoDocument::initDoc()

bool KChartPart::initDoc(InitDocFlags flags, QWidget* parentWidget)
{
    // Initialize the parameter set for this chart document
#if 0
    kdDebug(35001) << "================================================================" << endl;
    kdDebug(35001) << "InitDOC: flags = " << flags << endl;
    kdDebug(35001) << "================================================================" << endl;
#endif

    QString f;

    // Embedded documents are initially created like a normal empty
    // document.  If this is in KSpread or another program where the
    // data is external then the document will be updated later on in
    // the creation process anyway.
    if (flags == KoDocument::InitDocEmbedded) {
	initEmpty();
	return true;
    }

    // If we are supposed to create a new, empty document, then do so.
    if (flags == KoDocument::InitDocEmpty) {
	initEmpty();
	return true;
    }

    KoTemplateChooseDia::ReturnType  ret;
    KoTemplateChooseDia::DialogType  dlgtype;

    // If we must create a new document, then only present templates
    // to the user, otherwise also present existing documents and
    // recent documents.
    if (flags == KoDocument::InitDocFileNew )
	dlgtype = KoTemplateChooseDia::OnlyTemplates;
    else
	dlgtype = KoTemplateChooseDia::Everything;
    ret = KoTemplateChooseDia::choose( KChartFactory::global(), f,
                                       dlgtype, "kchart_template",
				       parentWidget );

    if ( ret == KoTemplateChooseDia::File ) {
	KURL url( f );
	return openURL( url );
    }
    else if ( ret == KoTemplateChooseDia::Empty ) {
	initEmpty();
	return true;
    }
    else if ( ret == KoTemplateChooseDia::Template ) {
		//TODO: Activate this for KOffice 1.5/2.0
// 		if ( f.endsWith("/templates/chart/.source/BarChart.chrt") ) {
// 			generateBarChartTemplate();
// 			return true;
// 		}
        QFileInfo fileInfo( f );
        QString fileName( fileInfo.dirPath( true ) + "/" +
            fileInfo.baseName() + ".chrt" );

        resetURL();
        bool ok = loadNativeFormat( fileName );
        if ( !ok )
            showLoadingErrorDialog();
        setEmpty();
        //initConfig();
        return ok;
    }

    return false;
}

void KChartPart::initEmpty()
{
    initNullChart();

    resetURL();
    setEmpty();
}


// This method creates the simplest chart imaginable:
// Data size 1x1, empty, no headers
//
void KChartPart::initNullChart()
{
    // Fill cells with data if there is none.
    //kdDebug(35001) << "Initialize null chart." << endl;

    // Empty data.  Note, we don't use (0,0) or (1,1) for the size
    // here, because otherwise KDChart won't draw anything
    m_currentData.expand(2, 2);
    m_params->setFirstRowAsLabel(false);
    m_params->setFirstColAsLabel(false);

    // Fill column and row labels.
    m_colLabels << QString("");
    m_rowLabels << QString("");

    setChartDefaults();

    m_params->setDrawSolidExcessArrows(true);
}


void KChartPart::generateBarChartTemplate()
{
    int  col;
    int  row;

    kdDebug()<<"KChartPart::initTestChart()\n";

    // Fill cells with data if there is none.
    if (m_currentData.rows() == 0) {
        //kdDebug(35001) << "Initialize with some data!!!" << endl;
        m_currentData.expand( 4, 4 );
        m_currentData.setUsedRows( 4 );
        m_currentData.setUsedCols( 4 );
        for (row = 0; row < 4; row++) {
            for (col = 0; col < 4; col++) {
                m_currentData.setCell(row, col,
				      static_cast <double> (row + col));

		// Fill column label, but only on the first iteration.
		if (row == 0) {
		    m_colLabels << i18n("Column %1").arg(col + 1);
		}
            }

	    // Fill row label.
	    m_rowLabels << i18n("Row %1").arg(row + 1);
	}
    }

    setChartDefaults();
    // FIXME: Should this go into setChartDefaults()?
    m_params->setDrawSolidExcessArrows(true);
}


KoView* KChartPart::createViewInstance( QWidget* parent, const char* name )
{
    return new KChartView( this, parent, name );
}


// ================================================================
//                              Painting


void KChartPart::paintContent( QPainter& painter, const QRect& rect,
			       bool /*transparent*/,
			       double /*zoomX*/, double /*zoomY*/ )
{
    int  numDatasets;

    // If params is 0, initDoc() has not been called.
    Q_ASSERT( m_params != 0 );

    KDChartAxisParams  xAxisParms;
    xAxisParms = m_params->axisParams( KDChartAxisParams::AxisPosBottom );

    // Handle data in rows or columns.
    //
    // This means getting row or column headers from the document and
    // set them as X axis labels or legend according to the current
    // setting.  Also, transpose the data if it should be displayed in
    // columns instead of in rows.


    // Create the displayData table.
    numDatasets = createDisplayData();

    // Create and set the axis labels and legend.
    QStringList  longLabels;
    QStringList  shortLabels;
    createLabelsAndLegend(longLabels, shortLabels);

    // Set the x axis labels.
    xAxisParms.setAxisLabelStringLists( &longLabels, &shortLabels );
    m_params->setAxisParams(KDChartAxisParams::AxisPosBottom, xAxisParms);


    // Handle some types or subtypes of charts specially, notably:
    //  - Bar charts with lines in them

    if ( m_params->chartType() == KChartParams::Bar) {
	if ( m_params->barNumLines() > 0 ) {

	    // If this is a bar chart and the user wants a few lines in
	    // it, we need to create an additional chart in the same
	    // drawing area.

	    // Specify that we want to have an additional chart.
	    m_params->setAdditionalChartType( KDChartParams::Line );

	    const int numBarDatasets = numDatasets - m_params->barNumLines();

	    // Assign the datasets to the charts: DataEntry, from, to, chart#
	    m_params->setChartSourceMode( KDChartParams::DataEntry,
					  0, numBarDatasets - 1,
					  0 ); // The bar chart
	    m_params->setChartSourceMode( KDChartParams::DataEntry,
					  numBarDatasets, numDatasets - 1,
					  1 ); // The line chart
	}
	else {
	    // Otherwise we don't want any extra chart.
	    m_params->setAdditionalChartType( KDChartParams::NoType );
	}
    }

    // Ok, we have now created a data set for display, and params with
    // suitable legends and axis labels.  Now start the real painting.

    // Handle transparency.
    // Wrong: this flickers; better do this as part of the double-buffering.
    //if ( !transparent )
    //    painter.eraseRect( rect );

    // ## TODO: support zooming

    // Double-buffering
    if ( m_bufferPixmap.width() < rect.width()
	 || m_bufferPixmap.height() < rect.height() )
    {
    	m_bufferPixmap.resize( rect.size() );
    }

    QPainter bufferPainter( &m_bufferPixmap );

    // We only need to draw the document rectangle "rect".
    KDChart::paint( &bufferPainter, m_params, &m_displayData, 0, &rect );

    // This is always the empty rect...
    // Shouldn't creating a QPainter in a paintEvent set up clipping automatically?
    // I thought it did (DF)
    //const QRect clipRect = painter.clipRegion().boundingRect();
    //painter.drawPixmap( clipRect.topLeft(), m_bufferPixmap, clipRect );

    painter.drawPixmap( 0, 0, m_bufferPixmap );
}


// Create the data table m_displayData from m_currentData, taking into
// account if the first row or line contains headers.  The chart type
// HiLo demands special handling.
//
// Return number of datasets.
//
// Note: While the current KD Chart 1.1.3 version is still expecting data
//       to be in rows, the upcoming KD Chart 2.0 release will be using
//       data in columns instead, to it will be matching KSpread's way.
//       -khz, 2005-11-15
//
// FIXME: Rewrite so that we only copy data when necessary.
//        On the other hand, the next version of KDChart is able to
//        get data directly without storing it into a KDChartData
//        class first, so we might never need to.
//
int  KChartPart::createDisplayData()
{
    int  rowOffset   = 0;
    int  colOffset   = 0;
    int  numDatasets = 0;

    if ( !canChangeValue() ) {
	if ( m_params->firstRowAsLabel() )
	    rowOffset++;
	if ( m_params->firstColAsLabel() )
	    colOffset++;
    }

    // After this sequence, m_DisplayData contains the data in the
    // correct transposition, and the X axis and the legend contain
    // the correct labels.
    QVariant  value1;
    QVariant  value2;
    int       prop;
    if (m_params->dataDirection() == KChartParams::DataRows) {
	// Data is handled in rows.  This is the way KDChart works also.

	numDatasets = m_currentData.usedRows() - rowOffset;
	m_displayData.expand( numDatasets,
			      m_currentData.usedCols() - colOffset );

	// Remove the first row and/or col if they are used for headers.
	for (uint row = rowOffset; row < m_currentData.usedRows(); row++) {
	    for (uint col = colOffset; col < m_currentData.usedCols(); col++) {
		if ( m_currentData.cellContent( row, col,
						value1, value2, prop ) ) {
		    m_displayData.setCell(row - rowOffset, col - colOffset,
					  value1, value2);
		    m_displayData.setProp(row - rowOffset, col - colOffset,
					  prop);
                }
	    }
	}
    }
    else {
	// Data is handled in columns.  We will have to transpose
	// everything since KDChart wants its data in rows.

	// Resize displayData so that the transposed data has room.
	numDatasets = m_currentData.usedCols() - colOffset;
	m_displayData.expand( numDatasets,
			      m_currentData.usedRows() - rowOffset );

	// Copy data and transpose it.
	for (uint row = colOffset; row < m_currentData.usedCols(); row++) {
	    for (uint col = rowOffset; col < m_currentData.usedRows(); col++) {
                if ( m_currentData.cellContent( col, row,
						value1, value2, prop ) ) {
		    m_displayData.setCell(row - colOffset, col - rowOffset,
					  value1, value2);
		    m_displayData.setProp(row - colOffset, col - rowOffset,
					  prop);
                }
	    }
	}
    }

    // If this is a HiLo chart, we need to manually create the correct
    // values.  This is not done by KDChart.
    //
    // Here we don't need to transpose, since we can start from the
    // newly generated displayData.
    if (m_params->chartType() == KChartParams::HiLo) {
	KDChartTableData  tmpData = m_displayData;

	// Calculate the min, max, open and close values for each row.
	m_displayData.expand(tmpData.usedRows(), 4);
	for (uint row = 0; row < tmpData.usedRows(); row++) {
	    double  minVal   = DBL_MAX;
	    double  maxVal   = -DBL_MAX;

	    // Calculate min and max for this row.
	    //
	    // Note that we have already taken care of different data
	    // directions above.
	    for (uint col = 0; col < tmpData.usedCols(); col++) {
		double  data = tmpData.cellVal(row, col).toDouble();

		if (data < minVal)
		    minVal = data;
		if (data > maxVal)
		    maxVal = data;
	    }
	    m_displayData.setCell(row, 0, minVal); // min
	    m_displayData.setCell(row, 1, maxVal); // max
	    m_displayData.setCell(row, 2, tmpData.cellVal(row, 0).toDouble());   // open
	    m_displayData.setCell(row, 3,                          // close
				  tmpData.cellVal(row, tmpData.usedCols() - 1).toDouble());
	}
    }

    return numDatasets;
}


void KChartPart::createLabelsAndLegend( QStringList  &longLabels,
					QStringList  &shortLabels )
{
    longLabels.clear();
    shortLabels.clear();

    const uint dataColumnCount  = m_currentData.cols();
    const uint dataRowCount     = m_currentData.rows();
    const uint columnLabelCount = m_colLabels.count();
    const uint rowLabelCount    = m_rowLabels.count();

    // Handle HiLo charts separately.
    if (m_params->chartType() == KChartParams::HiLo) {

      // FIXME: In a HiLo chart, the Legend should be the same as the
      //        labels on the X Axis.  Should we disable one of them?

	// Set the correct X axis labels and legend.
	longLabels.clear();
	shortLabels.clear();
	if (m_params->dataDirection() == KChartParams::DataRows) {

	    // If data are in rows, then the X axis labels should be
	    // taken from the row headers.
	    for ( uint row = 0; row < dataRowCount ; row++ ) {

                QString label = (row < rowLabelCount) ? m_rowLabels[row] : QString::null;

                longLabels  << label;
		shortLabels << label.left( 3 );
	    }
	}
	else {
	    // If data are in columns, then the X axis labels should
	    // be taken from the column headers.
	    for ( uint col = 0; col < dataColumnCount; col++ ) {

                QString label = (col < columnLabelCount) ? m_colLabels[col] : QString::null;

                longLabels  << m_colLabels[col];
		shortLabels << m_colLabels[col].left( 3 );
	    }
	}
    }
    else if (m_params->dataDirection() == KChartParams::DataRows) {
	// Data is handled in rows.  This is the way KDChart works also.

	// Set X axis labels from column headers.
	for ( uint col = 0; col < dataColumnCount; col++ ) {

            QString label = (col < columnLabelCount) ? m_colLabels[col] : QString::null;

            longLabels  << label;
	    shortLabels << label.left( 3 );
	}

	// Set legend from row headers.
        for ( uint row = 0; row < dataRowCount; row++ ) {
            QString label = (row < rowLabelCount) ? m_rowLabels[row] : QString::null;

            m_params->setLegendText( row, label );
        }
    }
    else {
	// Data is handled in columns.

	// Set X axis labels from row headers.
	for ( uint row = 0; row < dataRowCount; row++ ) {

            QString label = (row < rowLabelCount) ? m_rowLabels[row] : QString::null;

            longLabels  << label;
	    shortLabels << label.left( 3 );
	}

	// Set legend from column headers.
        for ( uint col = 0; col < dataColumnCount ; col++ ) {
            QString label = (col < columnLabelCount) ? m_colLabels[col] : QString::null;

            m_params->setLegendText( col, label );
        }
    }
}



// ================================================================


void KChartPart::analyzeHeaders()
{
#if 0
    analyzeHeaders( m_currentData );
#else
    doSetData( m_currentData,
	       m_params->firstRowAsLabel(), m_params->firstColAsLabel());
#endif
}


// This function sets the data from an external source.  It is called,
// for instance, when the chart is initialized from a spreadsheet in
// KSpread.
//
void KChartPart::analyzeHeaders( const KDChartTableData& data )
{
    // FIXME(khz): replace this when automatic string detection works in KDChart
    // Does the top/left cell contain a string?
    bool isStringTopLeft = (data.cellVal( 0, 0 ).type() == QVariant::String);

    // Does the first row (without first cell) contain only strings?
    bool isStringFirstRow = true;
    for ( uint col = 1; isStringFirstRow && col < data.cols(); col++ ) {
        isStringFirstRow = (data.cellVal( 0, col ).type() == QVariant::String);
    }

    // Just in case, we only have 1 row, we never use it for label text.
    // This prevents a crash.
    //
    // FIXME: Wonder if this is still true for KDChart 1.1.3 / iw
    //        Disabling...
#if 1
    if ( data.rows() == 1 )
        isStringFirstRow = false;
#endif

    // Does the first column (without first cell) contain only strings?
    bool isStringFirstCol = true;
    for ( uint row = 1; isStringFirstCol && row < data.rows(); row++ ) {
        isStringFirstCol = (data.cellVal( row, 0 ).type() == QVariant::String);
    }

    // Just in case, we only have 1 column, we never use it for axis
    // label text => prevents crash.
#if 1
    if ( data.cols() == 1 )
        isStringFirstRow = FALSE;
#endif

    bool hasColHeader = false;
    bool hasRowHeader = false;

    // Let's check if we have a full axis label text column
    if ( isStringFirstCol && isStringTopLeft
	 || isStringFirstCol && isStringFirstRow )
        hasColHeader = true;

    // Let's check if we have a full label text row.
    if ( isStringFirstRow && isStringTopLeft
	 || isStringFirstCol && isStringFirstRow )
        hasRowHeader = true;

    m_params->setFirstRowAsLabel( hasRowHeader );
    m_params->setFirstColAsLabel( hasColHeader );

    doSetData(data, hasRowHeader, hasColHeader);
}



void KChartPart::doSetData( const KDChartTableData&  data,
			    bool  firstRowHeader,
			    bool  firstColHeader )
{
    uint  rowStart = 0;
    uint  colStart = 0;
    uint  col;
    uint  row;

    // From this point, we know that the labels and legend are going
    // to be taken from the data if firstRowHeader or firstColheader
    // is true.

    if (firstRowHeader)
        rowStart = 1;
    if (firstColHeader)
        colStart = 1;

    // Generate m_rowlabels from the column headers if applicable.
    m_rowLabels.clear();
    if ( firstColHeader ) {
	for( row = rowStart; row < data.rows(); row++ ) {
	    m_rowLabels << data.cellVal( row, 0 ).toString();
	}
    }
    else {
	for( row = rowStart; row < data.rows(); row++ )
	    m_rowLabels << "";

	// FIXME: Check what this does, and if we don't have to check
	//        the data order (rows / cols).
	m_params->setLegendSource( KDChartParams::LegendAutomatic );
    }

    // Generate X labels from the row headers if applicable
    m_colLabels.clear();
    if ( firstRowHeader ) {
        for( col = colStart; col < data.cols(); col++ ) {
	    m_colLabels << data.cellVal( 0, col ).toString();
	}
    }
    else {
	for( col = colStart; col < data.cols(); col++ )
	    m_colLabels << "";
    }

    // Doesn't hurt if data == m_currentData, but necessary if not.
    m_currentData = data;

    //setChartDefaults();

    emit docChanged();
}


void KChartPart::resizeData( int rows, int cols )
{
    m_currentData.expand( rows, cols );
    m_currentData.setUsedRows( rows );
    m_currentData.setUsedCols( cols );
}


void KChartPart::setCellData( int row, int column, const QVariant &val)
{
    m_currentData.setCell( row, column, val );
}


bool KChartPart::showWizard( QString &dataArea )
{
    KChartWizard  *wizard = new KChartWizard( this, m_parentWidget, "wizard" );

    connect( wizard, SIGNAL(finished()), this, SLOT(slotModified()) );

    wizard->setDataArea( dataArea );

    bool  ret = wizard->exec();

    delete wizard;
    return ret;
}


void KChartPart::initLabelAndLegend()
{
    // Labels and legends are automatically initialized to reasonable
    // default values in KDChart
}


// Set up some values for the chart Axis, that are not well chosen by
// default by KDChart.
//

void KChartPart::setChartDefaults()
{
  //
  // Settings for the Y axis.
  //
  KDChartAxisParams  yAxis;
  yAxis = m_params->axisParams( KDChartAxisParams::AxisPosLeft );

  // decimal symbol and thousands separator
  yAxis.setAxisLabelsRadix( KGlobal::locale()->decimalSymbol(),
			    KGlobal::locale()->thousandsSeparator() );

  m_params->setAxisParams( KDChartAxisParams::AxisPosLeft, yAxis );

  //
  // Settings for the X axis.
  //
  KDChartAxisParams  xAxis;
  xAxis = m_params->axisParams( KDChartAxisParams::AxisPosBottom );

  // These two shouldn't be necessary to set.
  xAxis.setAxisFirstLabelText();
  xAxis.setAxisLastLabelText();

  m_params->setAxisParams( KDChartAxisParams::AxisPosBottom, xAxis );

  // Other parameters for various things.
  m_params->setLineColor();

  // Setting the background layer.
  KDFrame frame;
  frame.setBackground( QBrush( QColor( 230, 222, 222 ) ) );
  m_params->setFrame( KDChartEnums::AreaInnermost, frame, 0, 0, 0, 0 );
}


// ================================================================
//                     Loading and Storing


// ----------------------------------------------------------------
//                 Save and Load program configuration



void KChartPart::loadConfig( KConfig *conf )
{
    conf->setGroup("ChartParameters");

    // TODO: the fonts
    // PENDING(kalle) Put the applicable ones of these back in
    //   QFont tempfont;
    //   tempfont = conf->readFontEntry("titlefont", &titlefont);
    //   setTitleFont(tempfont);
    //   tempfont = conf->readFontEntry("ytitlefont", &ytitlefont);
    //   setYTitleFont(tempfont);
    //   tempfont = conf->readFontEntry("xtitlefont", &xtitlefont);
    //   setXTitleFont(tempfont);
    //   tempfont = conf->readFontEntry("yaxisfont", &yaxisfont);
    //   setYAxisFont(tempfont);
    //   tempfont = conf->readFontEntry("xaxisfont", &xaxisfont);
    //   setXAxisFont(tempfont);
    //   tempfont = conf->readFontEntry("labelfont", &labelfont);
    //   setLabelFont(tempfont);
    //   tempfont = conf->readFontEntry("annotationfont", &annotationfont);
    //   setAnnotationFont(tempfont);

    //   ylabel_fmt = conf->readEntry("ylabel_fmt", ylabel_fmt );
    //   ylabel2_fmt = conf->readEntry("ylabel2_fmt", ylabel2_fmt);
    //   xlabel_spacing = conf->readNumEntry("xlabel_spacing");
    //   ylabel_density = conf->readNumEntry("ylabel_density", ylabel_density);
    //   requested_ymin = conf->readDoubleNumEntry("requested_ymin", requested_ymin);
    //   requested_ymax = conf->readDoubleNumEntry("requested_ymax", requested_ymax );
    //   requested_yinterval = conf->readDoubleNumEntry("requested_yinterval",
    // 					   requested_yinterval);
    //   shelf = conf->readBoolEntry("shelf", shelf);
    //   grid = conf->readBoolEntry("grid", grid);
    //   xaxis = conf->readBoolEntry("xaxis", xaxis);
    //   yaxis = conf->readBoolEntry("yaxis", yaxis);
    //   yaxis2 = conf->readBoolEntry("yaxis2", yaxis);
    //   llabel = conf->readBoolEntry("llabel", llabel);
    //   yval_style = conf->readNumEntry("yval_style", yval_style);
    //   stack_type = (KChartStackType)conf->readNumEntry("stack_type", stack_type);
    m_params->setLineMarker(conf->readBoolEntry("lineMarker",
						m_params->lineMarker()));
    m_params->setThreeDBarDepth( conf->readDoubleNumEntry("_3d_depth",
							  m_params->threeDBarDepth() ) );
    m_params->setThreeDBarAngle( conf->readNumEntry( "_3d_angle",
						     m_params->threeDBarAngle() ) );

    KDChartAxisParams  leftparams;
    leftparams = m_params->axisParams( KDChartAxisParams::AxisPosLeft );
    KDChartAxisParams  rightparams;
    rightparams = m_params->axisParams( KDChartAxisParams::AxisPosRight );
    KDChartAxisParams  bottomparams;
    bottomparams = m_params->axisParams( KDChartAxisParams::AxisPosBottom );

    bottomparams.setAxisLineColor( conf->readColorEntry( "XTitleColor", 0 ) );
    leftparams.setAxisLineColor( conf->readColorEntry( "YTitleColor", 0 ) );
    rightparams.setAxisLineColor( conf->readColorEntry( "YTitle2Color", 0 ) );
    bottomparams.setAxisLabelsColor( conf->readColorEntry( "XLabelColor", 0 ) );
    leftparams.setAxisLabelsColor( conf->readColorEntry( "YLabelColor", 0 ) );
    rightparams.setAxisLabelsColor( conf->readColorEntry( "YLabel2Color", 0 ) );
    leftparams.setAxisGridColor( conf->readColorEntry( "GridColor", 0 ) );
    m_params->setOutlineDataColor( conf->readColorEntry( "LineColor", 0 ) );
    m_params->setAxisParams( KDChartAxisParams::AxisPosLeft,
                            leftparams );
    m_params->setAxisParams( KDChartAxisParams::AxisPosRight,
                            rightparams );
    m_params->setAxisParams( KDChartAxisParams::AxisPosBottom,
                            bottomparams );

    //   hlc_style = (KChartHLCStyle)conf->readNumEntry("hlc_style", hlc_style);
    //   hlc_cap_width = conf->readNumEntry("hlc_cap_width", hlc_cap_width);
    //   // TODO: Annotation font
    //   num_scatter_pts = conf->readNumEntry("num_scatter_pts", num_scatter_pts);
    //   // TODO: Scatter type
    //   thumbnail = conf->readBoolEntry("thumbnail", thumbnail);
    //   thumblabel = conf->readEntry("thumblabel", thumblabel);
    //   border = conf->readBoolEntry("border", border);
    //   BGColor = conf->readColorEntry("BGColor", &BGColor);
    //   PlotColor = conf->readColorEntry("PlotColor", &PlotColor);
    //   VolColor = conf->readColorEntry("VolColor", &VolColor);
    //   EdgeColor = conf->readColorEntry("EdgeColor", &EdgeColor);
    //   loadColorArray(conf, &SetColor, "SetColor");
    //   loadColorArray(conf, &ExtColor, "ExtColor");
    //   loadColorArray(conf, &ExtVolColor, "ExtVolColor");
    //   transparent_bg = conf->readBoolEntry("transparent_bg", transparent_bg);
    //   // TODO: explode, missing
    //   percent_labels = (KChartPercentType)conf->readNumEntry("percent_labels",
    // 							 percent_labels);
    //   label_dist = conf->readNumEntry("label_dist", label_dist);
    //   label_line = conf->readBoolEntry("label_line", label_line);
    m_params->setChartType( (KChartParams::ChartType)conf->readNumEntry( "type", m_params->chartType() ) );
    //   other_threshold = conf->readNumEntry("other_threshold", other_threshold);

    //   backgroundPixmapName = conf->readPathEntry( "backgroundPixmapName" );
    //   if( !backgroundPixmapName.isNull() ) {
    //     backgroundPixmap.load( locate( "wallpaper", backgroundPixmapName ));
    //     backgroundPixmapIsDirty = true;
    //   } else
    //     backgroundPixmapIsDirty = false;
    //   backgroundPixmapScaled = conf->readBoolEntry( "backgroundPixmapScaled", true );
    //   backgroundPixmapCentered = conf->readBoolEntry( "backgroundPixmapCentered", true );
    //   backgroundPixmapIntensity = conf->readDoubleNumEntry( "backgroundPixmapIntensity", 0.25 );
}


void KChartPart::defaultConfig(  )
{
    delete m_params;
    m_params = new KChartParams( this );
    setChartDefaults();
}


void KChartPart::saveConfig( KConfig *conf )
{
    conf->setGroup("ChartParameters");

    // PENDING(kalle) Put some of these back in
    // the fonts
    //   conf->writeEntry("titlefont", titlefont);
    //   conf->writeEntry("ytitlefont", ytitlefont);
    //   conf->writeEntry("xtitlefont", xtitlefont);
    //   conf->writeEntry("yaxisfont", yaxisfont);
    //   conf->writeEntry("xaxisfont", xaxisfont);
    //   conf->writeEntry("labelfont", labelfont);

    //   conf->writeEntry("ylabel_fmt", ylabel_fmt);
    //   conf->writeEntry("ylabel2_fmt", ylabel2_fmt);
    //   conf->writeEntry("xlabel_spacing", xlabel_spacing);
    //   conf->writeEntry("ylabel_density", ylabel_density);
    //   conf->writeEntry("requested_ymin", requested_ymin);
    //   conf->writeEntry("requested_ymax", requested_ymax);
    //   conf->writeEntry("requested_yinterval", requested_yinterval);

    //   conf->writeEntry("shelf", shelf);
    //   conf->writeEntry("grid", grid );
    //   conf->writeEntry("xaxis", xaxis);
    //   conf->writeEntry("yaxis", yaxis);
    //   conf->writeEntry("yaxis2", yaxis2);
    //   conf->writeEntry("llabel", llabel);
    //   conf->writeEntry("yval_style", yval_style );
    //   conf->writeEntry("stack_type", (int)stack_type);

    conf->writeEntry( "_3d_depth", m_params->threeDBarDepth() );
    conf->writeEntry( "_3d_angle", m_params->threeDBarAngle() );

    KDChartAxisParams leftparams;
    leftparams   = m_params->axisParams( KDChartAxisParams::AxisPosLeft );
    KDChartAxisParams rightparams;
    rightparams  = m_params->axisParams( KDChartAxisParams::AxisPosRight );
    KDChartAxisParams bottomparams;
    bottomparams = m_params->axisParams( KDChartAxisParams::AxisPosBottom );
    conf->writeEntry( "LineColor",    m_params->outlineDataColor() );
    conf->writeEntry( "XTitleColor",  bottomparams.axisLineColor() );
    conf->writeEntry( "YTitleColor",  leftparams.axisLineColor() );
    conf->writeEntry( "YTitle2Color", rightparams.axisLineColor() );
    conf->writeEntry( "XLabelColor",  bottomparams.axisLabelsColor() );
    conf->writeEntry( "YLabelColor",  leftparams.axisLabelsColor() );
    conf->writeEntry( "YLabel2Color", rightparams.axisLabelsColor() );
    conf->writeEntry( "GridColor",    leftparams.axisGridColor() );

    //   conf->writeEntry("hlc_style", (int)hlc_style);
    //   conf->writeEntry("hlc_cap_width", hlc_cap_width );
    //   // TODO: Annotation type!!!
    //   conf->writeEntry("annotationfont", annotationfont);
    //   conf->writeEntry("num_scatter_pts", num_scatter_pts);
    //   // TODO: Scatter type!!!
    //   conf->writeEntry("thumbnail", thumbnail);
    //   conf->writeEntry("thumblabel", thumblabel);
    //   conf->writeEntry("thumbval", thumbval);
    //   conf->writeEntry("border", border);
    //   conf->writeEntry("BGColor", BGColor);
    //   conf->writeEntry("PlotColor", PlotColor);
    //   conf->writeEntry("VolColor", VolColor);
    //   conf->writeEntry("EdgeColor", EdgeColor);
    //   saveColorArray(conf, &SetColor, "SetColor");
    //   saveColorArray(conf, &ExtColor, "ExtColor");
    //   saveColorArray(conf, &ExtVolColor, "ExtVolColor");


    //   conf->writeEntry("transparent_bg", transparent_bg);
    //   // TODO: explode, missing
    //   conf->writeEntry("percent_labels",(int) percent_labels );
    //   conf->writeEntry("label_dist", label_dist);
    //   conf->writeEntry("label_line", label_line);
    conf->writeEntry( "type", (int) m_params->chartType() );
    //   conf->writeEntry("other_threshold", other_threshold);

    // background pixmap stuff
    //   if( !backgroundPixmapName.isNull() )
    // 	conf->writePathEntry( "backgroundPixmapName", backgroundPixmapName );
    //   conf->writeEntry( "backgroundPixmapIsDirty", backgroundPixmapIsDirty );
    //   conf->writeEntry( "backgroundPixmapScaled", backgroundPixmapScaled );
    //   conf->writeEntry( "backgroundPixmapCentered", backgroundPixmapCentered );
    //   conf->writeEntry( "backgroundPixmapIntensity", backgroundPixmapIntensity );
    conf->writeEntry( "lineMarker", (int) m_params->lineMarker());
}


// ----------------------------------------------------------------
//              Save and Load OpenDocument file format


bool KChartPart::loadOasis( const QDomDocument& doc,
			    KoOasisStyles&      oasisStyles,
			    const QDomDocument& /*settings*/,
			    KoStore            *store )
{
    kdDebug(35001) << "kchart loadOasis called" << endl;

    // Set some sensible defaults.
    setChartDefaults();

    QDomElement  content = doc.documentElement();
    QDomElement  bodyElem ( KoDom::namedItemNS( content,
						KoXmlNS::office, "body" ) );
    if ( bodyElem.isNull() ) {
        kdError(32001) << "No office:body found!" << endl;
        setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No office:body tag found." ) );
        return false;
    }

    // Get the office:chart element.
    QDomElement officeChartElem = KoDom::namedItemNS( bodyElem,
						      KoXmlNS::office, "chart" );
    if ( officeChartElem.isNull() ) {
        kdError(32001) << "No office:chart found!" << endl;
        QDomElement  childElem;
        QString      localName;
        forEachElement( childElem, bodyElem ) {
            localName = childElem.localName();
        }

        if ( localName.isEmpty() )
            setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No tag found inside office:body." ) );
        else
            setErrorMessage( i18n( "This document is not a chart, but %1. Please try opening it with the appropriate application." ).arg( KoDocument::tagNameToDocumentType( localName ) ) );

        return false;
    }

    QDomElement chartElem = KoDom::namedItemNS( officeChartElem,
						KoXmlNS::chart, "chart" );
    if ( chartElem.isNull() ) {
        setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No chart:chart tag found." ) );
        return false;
    }

    // Get the loading context and stylestack from the styles.
    KoOasisLoadingContext  loadingContext( this, oasisStyles, store );
    //KoStyleStack          &styleStack = loadingContext.styleStack();

#if 0  // Example code!!
    // load chart properties into the stylestack.
    styleStack.save();
    styleStack.setTypeProperties( "chart" ); // load chart properties
    loadingContext.fillStyleStack( chartElem, KoXmlNS::chart, "style-name" );

    const QString fillColor = styleStack.attributeNS( KoXmlNS::draw, "fill-color" );
    kdDebug() << "fillColor=" << fillColor << endl;

    styleStack.restore();
#endif

    // Load chart parameters, most of these are stored in the
    // chart:plot-area element within chart:chart.
    QString  errorMessage;
    bool     ok = m_params->loadOasis( chartElem, loadingContext, errorMessage,
				       store);
    if ( !ok ) {
        setErrorMessage( errorMessage );
        return false;
    }

    // TODO Load data direction (see loadAuxiliary)

    // Load the data table.
    QDomElement tableElem = KoDom::namedItemNS( chartElem,
						KoXmlNS::table, "table" );
    if ( !tableElem.isNull() ) {
        ok = loadOasisData( tableElem );
        if ( !ok )
            return false; // TODO setErrorMessage
    }

    return true;
}


bool KChartPart::loadOasisData( const QDomElement& tableElem )
{
    int          numberHeaderColumns = 0;
    QDomElement  tableHeaderColumns = KoDom::namedItemNS( tableElem,
							  KoXmlNS::table,
							  "table-header-columns" );

    QDomElement  elem;
    forEachElement( elem, tableHeaderColumns ) {
        if ( elem.localName() == "table-column" ) {
            int repeated = elem.attributeNS( KoXmlNS::table, "number-columns-repeated", QString::null ).toInt();
            numberHeaderColumns += QMAX( 1, repeated );
        }
    }

    // With 0 you get no titles, and with more than 1 we ignore the others.
    Q_ASSERT( numberHeaderColumns == 1 );

    int numberDataColumns = 0;
    QDomElement tableColumns = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-columns" );
    forEachElement( elem, tableColumns ) {
        if ( elem.localName() == "table-column" ) {
            int repeated = elem.attributeNS( KoXmlNS::table, "number-columns-repeated", QString::null ).toInt();
            numberDataColumns += QMAX( 1, repeated );
        }
    }

    // Parse table-header-rows for the column names.
    m_colLabels.clear();
    QDomElement tableHeaderRows = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-header-rows" );
    if ( tableHeaderRows.isNull() )
        kdWarning(35001) << "No table-header-rows element found!" << endl;
    QDomElement tableHeaderRow = KoDom::namedItemNS( tableHeaderRows, KoXmlNS::table, "table-row" );
    if ( tableHeaderRow.isNull() )
        kdWarning(35001) << "No table-row inside table-header-rows!" << endl;

    int cellNum = 0;
    forEachElement( elem, tableHeaderRow ) {
        if ( elem.localName() == "table-cell" ) {
            ++cellNum;
            if ( cellNum > numberHeaderColumns ) {
                QDomElement pElem = KoDom::namedItemNS( elem, KoXmlNS::text, "p" );
                m_colLabels.append( pElem.text() );
            }
        }
    }
    numberDataColumns = QMAX( numberDataColumns, cellNum - numberHeaderColumns );
    if ( (int)m_colLabels.count() != numberDataColumns )
        kdWarning(35001) << "Got " << m_colLabels.count()
			 << " column titles, expected " << numberDataColumns
			 << endl;

    // Get the number of rows, and read row labels
    int          numberDataRows = 0;
    QDomElement  tableRows = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-rows" );

    m_rowLabels.clear();
    forEachElement( elem, tableRows ) {
        if ( elem.localName() == "table-row" ) {
            int repeated = elem.attributeNS( KoXmlNS::table, "number-rows-repeated", QString::null ).toInt();
            Q_ASSERT( repeated <= 1 ); // we don't handle yet the case where data rows are repeated (can this really happen?)
            numberDataRows += QMAX( 1, repeated );
            if ( numberHeaderColumns > 0 ) {
                QDomElement firstCell = KoDom::namedItemNS( elem, KoXmlNS::table, "table-cell" );
                QDomElement pElem = KoDom::namedItemNS( firstCell, KoXmlNS::text, "p" );
                m_rowLabels.append( pElem.text() );
            }
        }
    }

    kdDebug(35001) << "numberHeaderColumns=" << numberHeaderColumns
		   << " numberDataColumns=" << numberDataColumns
                   << " numberDataRows=" << numberDataRows << endl;

    if ( (int)m_rowLabels.count() != numberDataRows)
        kdWarning(35001) << "Got " << m_rowLabels.count()
			 << " row labels, expected " << numberDataRows << endl;

    m_currentData.expand( numberDataRows, numberDataColumns );
    m_currentData.setUsedCols( numberDataColumns );
    m_currentData.setUsedRows( numberDataRows );

    // Now really load the cells.
    int row = 0;
    QDomElement rowElem;
    forEachElement( rowElem, tableRows ) {
        if ( rowElem.localName() == "table-row" ) {
            int col = 0;
            int cellNum = 0;
            QDomElement cellElem;
            forEachElement( cellElem, rowElem ) {
                if ( cellElem.localName() == "table-cell" ) {
                    ++cellNum;
                    if ( cellNum > numberHeaderColumns ) {
                        QString valueType = cellElem.attributeNS( KoXmlNS::office, "value-type", QString::null );
                        if ( valueType != "float" )
                            kdWarning(35001) << "Don't know how to handle value-type " << valueType << endl;
                        else {
                            QString  value = cellElem.attributeNS( KoXmlNS::office, "value", QString::null );
                            double   val = value.toDouble();

                            m_currentData.setCell( row, col, val );
                        }
                        ++col;
                    }
                }
            }
            ++row;
        }
    }

    return true;
}


bool KChartPart::saveOasis( KoStore* store, KoXmlWriter* manifestWriter )
{
    manifestWriter->addManifestEntry( "content.xml", "text/xml" );
    KoOasisStore oasisStore( store );

    KoXmlWriter* contentWriter = oasisStore.contentWriter();
    if ( !contentWriter )
        return false;

    KoGenStyles mainStyles;

    KoXmlWriter* bodyWriter = oasisStore.bodyWriter();
    bodyWriter->startElement( "office:body" );
    bodyWriter->startElement( "office:chart" );
    bodyWriter->startElement( "chart:chart" );

    // Indent to indicate that this is inside some tags.
    {
        // Saves chart class, title, legend, plot-area
        m_params->saveOasis( bodyWriter, mainStyles );

	// Save the data table.
        saveOasisData( bodyWriter, mainStyles );
    }

    bodyWriter->endElement(); // chart:chart
    bodyWriter->endElement(); // office:chart
    bodyWriter->endElement(); // office:body

    contentWriter->startElement( "office:automatic-styles" );
    writeAutomaticStyles( *contentWriter, mainStyles );
    contentWriter->endElement(); // office:automatic-styles

    oasisStore.closeContentWriter();

    // Done with content.xml

#if 0
    if ( !store->open( "styles.xml" ) )
        return false;
    manifestWriter->addManifestEntry( "styles.xml", "text/xml" );
    saveOasisDocumentStyles( store, mainStyles, savingContext, saveFlag,
			     headerFooterContent );
    if ( !store->close() ) // done with styles.xml
        return false;
#endif

    return true;
}


void KChartPart::saveOasisData( KoXmlWriter* bodyWriter,
				KoGenStyles& mainStyles ) const
{
    Q_UNUSED( mainStyles );

    const int cols = m_currentData.usedCols()
                     ? QMIN(m_currentData.usedCols(), m_currentData.cols())
                     : m_currentData.cols();
    const int rows = m_currentData.usedRows()
                     ? QMIN(m_currentData.usedRows(), m_currentData.rows())
                     : m_currentData.rows();

    bodyWriter->startElement( "table:table" );
    bodyWriter->addAttribute( "table:name", "local-table" );

    // Exactly one header column, always.
    bodyWriter->startElement( "table:table-header-columns" );
    bodyWriter->startElement( "table:table-column" );
    bodyWriter->endElement(); // table:table-column
    bodyWriter->endElement(); // table:table-header-columns

    // Then "cols" columns
    bodyWriter->startElement( "table:table-columns" );
    bodyWriter->startElement( "table:table-column" );
    bodyWriter->addAttribute( "table:number-columns-repeated", cols );
    bodyWriter->endElement(); // table:table-column
    bodyWriter->endElement(); // table:table-columns

    // Exactly one header row, always.
    bodyWriter->startElement( "table:table-header-rows" );
    bodyWriter->startElement( "table:table-row" );

    // The first column in header row is just the header column - no title needed
    bodyWriter->startElement( "table:table-cell" );
    bodyWriter->addAttribute( "office:value-type", "string" );
    bodyWriter->startElement( "text:p" );
    bodyWriter->endElement(); // text:p
    bodyWriter->endElement(); // table:table-cell

    // Save column labels in the first header row, for instance:
    //          <table:table-cell office:value-type="string">
    //            <text:p>Column 1 </text:p>
    //          </table:table-cell>
    QStringList::const_iterator colLabelIt = m_colLabels.begin();
    for ( int col = 0; col < cols ; ++col ) {
        if ( colLabelIt != m_colLabels.end() ) {
            bodyWriter->startElement( "table:table-cell" );
            bodyWriter->addAttribute( "office:value-type", "string" );
            bodyWriter->startElement( "text:p" );
            bodyWriter->addTextNode( *colLabelIt );
            bodyWriter->endElement(); // text:p
            bodyWriter->endElement(); // table:table-cell
            ++colLabelIt;
        }
    }

    bodyWriter->endElement(); // table:table-row
    bodyWriter->endElement(); // table:table-header-rows
    bodyWriter->startElement( "table:table-rows" );

    QStringList::const_iterator rowLabelIt = m_rowLabels.begin();
    for ( int row = 0; row < rows ; ++row ) {
        bodyWriter->startElement( "table:table-row" );

        if ( rowLabelIt != m_rowLabels.end() ) {
            // Save row labels, similar to column labels
            bodyWriter->startElement( "table:table-cell" );
            bodyWriter->addAttribute( "office:value-type", "string" );

            bodyWriter->startElement( "text:p" );
            bodyWriter->addTextNode( *rowLabelIt );
            bodyWriter->endElement(); // text:p

            bodyWriter->endElement(); // table:table-cell
            ++rowLabelIt;
        }

        for ( int col = 0; col < cols; ++col ) {
            QVariant value( m_currentData.cellVal( row, col ) );
            QString  valType;
            QString  valStr;

            switch ( value.type() ) {
            case QVariant::Invalid:
		break;
            case QVariant::String:
		valType = "string";
		valStr  = value.toString();
		break;
            case QVariant::Double:
		valType = "float";
		valStr  = QString::number( value.toDouble(), 'g', DBL_DIG );
		break;
            case QVariant::DateTime:
		valType = "date";
		valStr  = ""; /* like in saveXML, but why? */
		break;
            default: {
                kdDebug(35001) << "ERROR: cell " << row << "," << col
                               << " has unknown type." << endl;
                }
            }

	    // Add the value type and the string to the XML tree.
            bodyWriter->startElement( "table:table-cell" );
            if ( !valType.isEmpty() ) {
                bodyWriter->addAttribute( "office:value-type", valType );
                if ( value.type() == QVariant::Double )
                    bodyWriter->addAttribute( "office:value", valStr );

                bodyWriter->startElement( "text:p" );
                bodyWriter->addTextNode( valStr );
                bodyWriter->endElement(); // text:p
            }
	    bodyWriter->endElement(); // table:table-cell
        }
        bodyWriter->endElement(); // table:table-row
    }

    bodyWriter->endElement(); // table:table-rows
    bodyWriter->endElement(); // table:table
}

void KChartPart::writeAutomaticStyles( KoXmlWriter& contentWriter, KoGenStyles& mainStyles ) const
{
    QValueList<KoGenStyles::NamedStyle> styles = mainStyles.styles( KoGenStyle::STYLE_AUTO );
    QValueList<KoGenStyles::NamedStyle>::const_iterator it = styles.begin();
    for ( ; it != styles.end() ; ++it ) {
        (*it).style->writeStyle( &contentWriter, mainStyles, "style:style", (*it).name, "style:chart-properties" );
    }

}

// ----------------------------------------------------------------
//             Save and Load old KChart file format


QDomDocument KChartPart::saveXML()
{
    QDomElement  tmpElem;

    //kdDebug(35001) << "kchart saveXML called" << endl;

    // The biggest part of the saving is done by KDChart itself, so we
    // don't have to do it.
    QDomDocument doc = m_params->saveXML( false );

    // ----------------------------------------------------------------
    // The rest of the saving has to be done by us.

    QDomElement docRoot = doc.documentElement();

    // Save auxiliary data.
    QDomElement aux = doc.createElement( "KChartAuxiliary" );
    docRoot.appendChild( aux );

    // The data direction (rows/columns).
    tmpElem = doc.createElement( "direction" );
    tmpElem.setAttribute( "value", (int) m_params->dataDirection() );
    aux.appendChild( tmpElem );

    tmpElem = doc.createElement( "dataaslabel" );
    tmpElem.setAttribute( "firstrow",
			  m_params->firstRowAsLabel() ? "true" : "false" );
    tmpElem.setAttribute( "firstcol",
			  m_params->firstColAsLabel() ? "true" : "false" );
    aux.appendChild( tmpElem );

    tmpElem = doc.createElement( "barnumlines" );
    tmpElem.setAttribute( "value", (int) m_params->barNumLines() );
    aux.appendChild( tmpElem );

    // Save the data values.
    QDomElement data = doc.createElement( "data" );
    docRoot.appendChild( data );

    int cols = m_currentData.usedCols()
             ? QMIN(m_currentData.usedCols(), m_currentData.cols())
             : m_currentData.cols();
    int rows = m_currentData.usedRows()
             ? QMIN(m_currentData.usedRows(), m_currentData.rows())
             : m_currentData.rows();
    data.setAttribute( "cols", cols );
    data.setAttribute( "rows", rows );
    kdDebug(35001) << "      writing  " << cols << "," << rows << "  (cols,rows)." << endl;

    for (int i=0; i!=rows; ++i) {
        for (int j=0; j!=cols; ++j) {
            QDomElement e = doc.createElement( "cell" );
            data.appendChild( e );
            QString valType;
            QVariant value( m_currentData.cellVal( i,j ) );
            switch ( value.type() ) {
                case QVariant::Invalid:  valType = "NoValue";   break;
                case QVariant::String:   valType = "String";    break;
                case QVariant::Double:   valType = "Double";    break;
                case QVariant::DateTime: valType = "DateTime";  break;
                default: {
                    valType = "(unknown)";
                    kdDebug(35001) << "ERROR: cell " << i << "," << j
				   << " has unknown type." << endl;
                }
            }

            e.setAttribute( "valType", valType );
            //kdDebug(35001) << "      cell " << i << "," << j
	    //	   << " saved with type '" << valType << "'." << endl;
            switch ( value.type() ) {
                case QVariant::String:  e.setAttribute( "value", value.toString() );
                              break;
                case QVariant::Double:  e.setAttribute( "value", QString::number( value.toDouble() ) );
                              break;
                case QVariant::DateTime:e.setAttribute( "value", "" );
                              break;
                default: {
                    e.setAttribute( "value", "" );
                    if( QVariant::Invalid != value.type() )
                        kdDebug(35001) << "ERROR: cell " << i << "," << j
				       << " has unknown type." << endl;
                }
            }
        }
    }

    return doc;
}


bool KChartPart::loadXML( QIODevice*, const QDomDocument& doc )
{
    kdDebug(35001) << "kchart loadXML called" << endl;

    // Set some sensible defaults.
    setChartDefaults();

    // First try to load the KDChart parameters.
    bool  result = m_params->loadXML( doc );

    // If went well, try to load the auxiliary data and the data...
    if (result) {
        result = loadAuxiliary(doc) && loadData( doc, m_currentData );
    }
    else {
	// ...but if it did, try to load the old XML format.
        result = loadOldXML( doc );
    }

    // If everything is OK, then get the headers from the KDChart parameters.
    if (result) {
        QStringList        legendLabels;
        KDChartAxisParams  params;
        params = m_params->axisParams( KDChartAxisParams::AxisPosBottom );

	// Get the legend.
	QString  str;
	uint     index = 0;
	while ((str = m_params->legendText(index++)) != QString::null)
	    legendLabels << str;

	if (m_params->dataDirection() == KChartParams::DataRows) {
	    m_colLabels = params.axisLabelStringList();
	    m_rowLabels = legendLabels;
	}
	else {
	    m_colLabels = legendLabels;
	    m_rowLabels = params.axisLabelStringList();
	}

    }

    m_params->setDrawSolidExcessArrows(true);

    return result;
}


// Load the auxiliary data.
//
// Currently, that means the data direction.
//
bool KChartPart::loadAuxiliary( const QDomDocument& doc )
{
    QDomElement  chart = doc.documentElement();
    QDomElement  aux   = chart.namedItem("KChartAuxiliary").toElement();

    // Older XML files might be missing this section.  That is OK; the
    // defaults will be used.
    if (aux.isNull())
	return true;

    QDomNode node = aux.firstChild();

    // If the aux section exists, it should contain data.
    while (!node.isNull()) {

	QDomElement e = node.toElement();
	if (e.isNull()) {
	    // FIXME: Should this be regarded as an error?
	    node = node.nextSibling();
	    continue;
	}

	// Check for direction
	if ( e.tagName() == "direction" ) {
	    if ( e.hasAttribute("value") ) {
		bool  ok;

		// Read the direction. On failure, use the default.
		int   dir = e.attribute("value").toInt(&ok);
		if ( !ok )
		    dir = (int) KChartParams::DataColumns;

		//kdDebug(35001) << "Got aux value \"direction\": " << dir << endl;
		m_params->setDataDirection( (KChartParams::DataDirection) dir );
	    }
	    else {
		kdDebug(35001) << "Error in direction tag." << endl;
	    }
	}

	// Check for first row / col as label
	else if ( e.tagName() == "dataaslabel" ) {
	    QString  val;

	    if ( e.hasAttribute("firstrow") ) {
		// Read the direction. On failure, use the default.
		val = e.attribute("firstrow");
		if ( val == "true" )
		    m_params->setFirstRowAsLabel( true );
		else
		    m_params->setFirstRowAsLabel( false );
	    }
	    else {
		kdDebug(35001) << "Error in barnumlines tag." << endl;
		m_params->setFirstRowAsLabel( false );
	    }

	    if ( e.hasAttribute("firstcol") ) {
		// Read the direction. On failure, use the default.
		val = e.attribute("firstcol");
		if ( val == "true" )
		    m_params->setFirstColAsLabel( true );
		else
		    m_params->setFirstColAsLabel( false );
	    }
	    else {
		kdDebug(35001) << "Error in barnumlines tag." << endl;
		m_params->setFirstColAsLabel( false );
	    }
	}

	// Check for number of lines in a bar chart.
	else if ( e.tagName() == "barnumlines" ) {
	    if ( e.hasAttribute("value") ) {
		bool  ok;

		// Read the number of lines. On failure, use the default.
		int   barNumLines = e.attribute("value").toInt(&ok);
		if ( !ok )
		    barNumLines = 0;

		//kdDebug(35001) << "Got aux value \"barnumlines\": "
		//	       << barNumLines << endl;
		m_params->setBarNumLines( barNumLines );
	    }
	    else {
		kdDebug(35001) << "Error in barnumlines tag." << endl;
	    }
	}
#if 0
	// Expand with more auxiliary types when needed.
	else if ( e.tagName() == "..." ) {
	}
	and so on...
#endif

	node = node.nextSibling();
    }

    return true;
}


bool KChartPart::loadData( const QDomDocument& doc,
			   KDChartTableData& m_currentData )
{
    kdDebug(35001) << "kchart loadData called" << endl;

    QDomElement chart = doc.documentElement();
    QDomElement data = chart.namedItem("data").toElement();
    bool ok;
    int cols = data.attribute("cols").toInt(&ok);
    kdDebug(35001) << "cols readed as:" << cols << endl;
    if ( !ok ){
         return false;
    }

    int rows = data.attribute("rows").toInt(&ok);
    if ( !ok ){
         return false;
    }

    kdDebug(35001) << rows << " x " << cols << endl;
    m_currentData.expand(rows, cols);
    m_currentData.setUsedCols( cols );
    m_currentData.setUsedRows( rows );
    kdDebug(35001) << "Expanded!" << endl;
    QDomNode n = data.firstChild();
    //QArray<int> tmpExp(rows*cols);
    //QArray<bool> tmpMissing(rows*cols);
    for (int i=0; i!=rows; i++) {
        for (int j=0; j!=cols; j++) {
            if (n.isNull()) {
                kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
                break;
            }
            QDomElement e = n.toElement();
            if ( !e.isNull() && e.tagName() == "cell" ) {
                // add the cell to the corresponding place...
                QVariant t;
                if ( e.hasAttribute("value") && e.hasAttribute("valType") ) {
                    QString valueType = e.attribute("valType").lower();
                    if ( "string" == valueType ) {
                        t = e.attribute("value");
                    }
                    else if ( "double" == valueType ) {
                        bool bOk;
                        double val = e.attribute("value").toDouble(&bOk);
                        if ( !bOk )
                            val = 0.0;
                        t = val;
                    /*
                    } else if ( "datetime" == valueType ) {
                        t = . . .
                    */
                    } else {
                        t.clear();
                        if ( "novalue" != valueType )
                            kdDebug(35001) << "ERROR: cell " << i << "," << j << " has unknown type '" << valueType << "'." << endl;
                    }
                } else
                    t.clear();

                m_currentData.setCell(i,j, t );

		/*
                if ( e.hasAttribute( "hide" ) ) {
                    tmpMissing[cols*j+i] = (bool)e.attribute("hide").toInt( &ok );
                    if ( !ok )
                        return false;
                } else {
                    tmpMissing[cols*j+i] = false;
                }
                if ( e.hasAttribute( "dist" ) ) {
                    tmpExp[cols*j+i] = e.attribute("dist").toInt( &ok );
                    if ( !ok )
                        return false;
                } else {
                    tmpExp[cols*j+i] = 0;
                }
		*/

                n = n.nextSibling();
            }
        }
    }
    /*
    m_params->missing=tmpMissing;
    m_params->explode=tmpExp;
    */
    return true;
}


// ----------------------------------------------------------------
//         Save and Load real old KChart file format


bool KChartPart::loadOldXML( const QDomDocument& doc )
{
    kdDebug(35001) << "kchart loadOldXML called" << endl;
    if ( doc.doctype().name() != "chart" )
        return false;

    kdDebug(35001) << "Ok, it is a chart" << endl;

    QDomElement chart = doc.documentElement();
    if ( chart.attribute( "mime" ) != "application/x-kchart" && chart.attribute( "mime" ) != "application/vnd.kde.kchart" )
        return false;

    kdDebug(35001) << "Mimetype ok" << endl;

#if 0
    QDomElement data = chart.namedItem("data").toElement();
    bool ok;
    int cols = data.attribute("cols").toInt(&ok);
    kdDebug(35001) << "cols readed as:" << cols << endl;
    if (!ok)  { return false; }
    int rows = data.attribute("rows").toInt(&ok);
    if (!ok)  { return false; }
    kdDebug(35001) << rows << " x " << cols << endl;
    m_currentData.expand(rows, cols);
    kdDebug(35001) << "Expanded!" << endl;
    QDomNode n = data.firstChild();
    QArray<int> tmpExp(rows*cols);
    QArray<bool> tmpMissing(rows*cols);

    for (int i=0; i!=rows; i++) {
        for (int j=0; j!=cols; j++) {
            if (n.isNull()) {
                kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
                break;
            }

            QDomElement e = n.toElement();
            if ( !e.isNull() && e.tagName() == "cell" ) {
                // add the cell to the corresponding place...
                double val = e.attribute("value").toDouble(&ok);
                if (!ok)  {  return false; }
                kdDebug(35001) << i << " " << j << "=" << val << endl;
                KoChart::Value t( val );
                // kdDebug(35001) << "Set cell for " << row << "," << col << endl;
                m_currentData.setCell(i,j,t);
                if ( e.hasAttribute( "hide" ) ) {
                    tmpMissing[cols*j+i] = (bool)e.attribute("hide").toInt( &ok );
                    if ( !ok )
                        return false;
                } else {
                    tmpMissing[cols*j+i] = false;
                }
                if ( e.hasAttribute( "dist" ) ) {
                    tmpExp[cols*j+i] = e.attribute("dist").toInt( &ok );
                    if ( !ok )
                        return false;
                } else {
                    tmpExp[cols*j+i] = 0;
                }

                n = n.nextSibling();
            }
        }
    }
    m_params->missing=tmpMissing;
    m_params->explode=tmpExp;
#endif


/*
  enum KChartType {
  KCHARTTYPE_LINE,
  KCHARTTYPE_AREA,
  KCHARTTYPE_BAR,
  KCHARTTYPE_HILOCLOSE,
  KCHARTTYPE_COMBO_LINE_BAR, aka, VOL[ume]
  KCHARTTYPE_COMBO_HLC_BAR,
  KCHARTTYPE_COMBO_LINE_AREA,
  KCHARTTYPE_COMBO_HLC_AREA,
  KCHARTTYPE_3DHILOCLOSE,
  KCHARTTYPE_3DCOMBO_LINE_BAR,
  KCHARTTYPE_3DCOMBO_LINE_AREA,
  KCHARTTYPE_3DCOMBO_HLC_BAR,
  KCHARTTYPE_3DCOMBO_HLC_AREA,
  KCHARTTYPE_3DBAR,
  KCHARTTYPE_3DAREA,
  KCHARTTYPE_3DLINE,
  KCHARTTYPE_3DPIE,
  KCHARTTYPE_2DPIE
  };
*/
    bool ok;
    QDomElement params = chart.namedItem( "params" ).toElement();
    if ( params.hasAttribute( "type" ) ) {
        int type=params.attribute("type").toInt( &ok );
        if ( !ok )
            return false;
        switch(type)
        {
        case 1:
            m_params->setChartType(KChartParams::Line);
            break;
        case 2:
            m_params->setChartType(KChartParams::Area);
            break;
        case 3:
            m_params->setChartType(KChartParams::Bar);
            break;
        case 4:
            m_params->setChartType(KChartParams::HiLo);
            break;
        case 5:
        case 6:
        case 7:
        case 8:
            /*     KCHARTTYPE_COMBO_LINE_BAR, aka, VOL[ume]
                   KCHARTTYPE_COMBO_HLC_BAR,
                   KCHARTTYPE_COMBO_LINE_AREA,
                   KCHARTTYPE_COMBO_HLC_AREA,
            */
            /* line by default*/
            m_params->setChartType(KChartParams::Line);
            break;
        case 9:
            m_params->setChartType(KChartParams::HiLo);
            break;
        case 10:
            m_params->setChartType(KChartParams::Bar);
            break;
        case 11:
            m_params->setChartType(KChartParams::Area);
            break;
        case 12:
            m_params->setChartType(KChartParams::Bar);
            break;
        case 13:
            m_params->setChartType(KChartParams::Area);
            break;
        case 14:
            m_params->setChartType(KChartParams::Bar);
            break;
        case 15:
            m_params->setChartType(KChartParams::Area);
            break;
        case 16:
            m_params->setChartType(KChartParams::Line);
            break;
        case 17:
        case 18:
            m_params->setChartType(KChartParams::Pie);
            break;

        }
        if ( !ok )
            return false;
    }
#if 0
    if ( params.hasAttribute( "subtype" ) ) {
        m_params->stack_type = (KChartStackType)params.attribute("subtype").toInt( &ok );
        if ( !ok )
            return false;
    }
    if ( params.hasAttribute( "hlc_style" ) ) {
        m_params->hlc_style = (KChartHLCStyle)params.attribute("hlc_style").toInt( &ok );
        if ( !ok )
            return false;
    }
    if ( params.hasAttribute( "hlc_cap_width" ) ) {
        m_params->hlc_cap_width = (short)params.attribute( "hlc_cap_width" ).toShort( &ok );
        if ( !ok )
            return false;
    }

    QDomElement title = params.namedItem( "title" ).toElement();
    if ( !title.isNull()) {
        QString t = title.text();
        m_params->title=t;
    }
    QDomElement titlefont = params.namedItem( "titlefont" ).toElement();
    if ( !titlefont.isNull()) {
        QDomElement font = titlefont.namedItem( "font" ).toElement();
        if ( !font.isNull() )
            m_params->setTitleFont(toFont(font));
    }
    QDomElement xtitle = params.namedItem( "xtitle" ).toElement();
    if ( !xtitle.isNull()) {
        QString t = xtitle.text();
        m_params->xtitle=t;
    }
    QDomElement xtitlefont = params.namedItem( "xtitlefont" ).toElement();
    if ( !xtitlefont.isNull()) {
        QDomElement font = xtitlefont.namedItem( "font" ).toElement();
        if ( !font.isNull() )
            m_params->setXTitleFont(toFont(font));
    }
    QDomElement ytitle = params.namedItem( "ytitle" ).toElement();
    if ( !ytitle.isNull()) {
        QString t = ytitle.text();
        m_params->ytitle=t;
    }
    QDomElement ytitle2 = params.namedItem( "ytitle2" ).toElement();
    if ( !ytitle2.isNull()) {
        QString t = ytitle2.text();
        m_params->ytitle2=t;
    }
    QDomElement ytitlefont = params.namedItem( "ytitlefont" ).toElement();
    if ( !ytitlefont.isNull()) {
        QDomElement font = ytitlefont.namedItem( "font" ).toElement();
        if ( !font.isNull() )
            m_params->setYTitleFont(toFont(font));
    }
    QDomElement ylabelfmt = params.namedItem( "ylabelfmt" ).toElement();
    if ( !ylabelfmt.isNull()) {
        QString t = ylabelfmt.text();
        m_params->ylabel_fmt=t;
    }
    QDomElement ylabel2fmt = params.namedItem( "ylabel2fmt" ).toElement();
    if ( !ylabel2fmt.isNull()) {
        QString t = ylabel2fmt.text();
        m_params->ylabel2_fmt=t;
    }
    QDomElement labelfont = params.namedItem( "labelfont" ).toElement();
    if ( !labelfont.isNull()) {
        QDomElement font = labelfont.namedItem( "font" ).toElement();
        if ( !font.isNull() )
            m_params->setLabelFont(toFont(font));
    }

    QDomElement yaxisfont = params.namedItem( "yaxisfont" ).toElement();
    if ( !yaxisfont.isNull()) {
        QDomElement font = yaxisfont.namedItem( "font" ).toElement();
        if ( !font.isNull() )
            m_params->setYAxisFont(toFont(font));
    }

    QDomElement xaxisfont = params.namedItem( "xaxisfont" ).toElement();
    if ( !xaxisfont.isNull()) {
        QDomElement font = xaxisfont.namedItem( "font" ).toElement();
        if ( !font.isNull() )
            m_params->setXAxisFont(toFont(font));
    }
    QDomElement annotationFont = params.namedItem("annotationfont").toElement();
    if ( !annotationFont.isNull()) {
        QDomElement font = annotationFont.namedItem( "font" ).toElement();
        if ( !font.isNull() )
            m_params->setAnnotationFont(toFont(font));
    }

    QDomElement yaxis = params.namedItem( "yaxis" ).toElement();
    if ( !yaxis.isNull()) {
        if (yaxis.hasAttribute( "yinterval" )) {
            m_params->requested_yinterval= yaxis.attribute("yinterval").toDouble( &ok );
            if ( !ok ) return false;
        }
        if (yaxis.hasAttribute( "ymin" )) {
            m_params->requested_ymin= yaxis.attribute("ymin").toDouble( &ok );
            if ( !ok ) return false;
        }
        if (yaxis.hasAttribute( "ymax" ) ) {
            m_params->requested_ymax= yaxis.attribute("ymax").toDouble( &ok );
            if ( !ok ) return false;
        }
    }
#endif

    QDomElement graph = params.namedItem( "graph" ).toElement();
    if (!graph.isNull()) {
        if (graph.hasAttribute( "grid" )) {
            bool b=(bool) graph.attribute("grid").toInt( &ok );
            m_params->setAxisShowGrid(KDChartAxisParams::AxisPosLeft,b );
            m_params->setAxisShowGrid(KDChartAxisParams::AxisPosBottom,b );
            if (!ok) return false;
        }
        if (graph.hasAttribute( "xaxis" )) {
            bool b=(bool) graph.attribute("xaxis").toInt( &ok );
            if (!ok) return false;
            m_params->setAxisVisible(KDChartAxisParams::AxisPosBottom,b);
        }
        if (graph.hasAttribute( "yaxis" )) {
            bool b=(bool) graph.attribute("yaxis").toInt( &ok );
            if (!ok) return false;
            m_params->setAxisVisible(KDChartAxisParams::AxisPosLeft,b);
        }
#if 0
        //no implemented
        if (graph.hasAttribute( "shelf" )) {
            m_params->shelf=(bool) graph.attribute("shelf").toInt( &ok );
            if (!ok) return false;
        }
#endif
        if (graph.hasAttribute( "yaxis2" )) {
            bool b=(bool) graph.attribute("yaxis2").toInt( &ok );
            if (!ok) return false;
            m_params->setAxisVisible(KDChartAxisParams::AxisPosRight,b);
        }

#if 0
        //no implemented
        if (graph.hasAttribute( "ystyle" )) {
            m_params->yval_style=(bool) graph.attribute("ystyle").toInt( &ok );
            if (!ok) return false;
        }
        if (graph.hasAttribute( "border" )) {
            m_params->border=(bool) graph.attribute("border").toInt( &ok );
            if (!ok) return false;
        }
        if (graph.hasAttribute( "transbg" )) {
            m_params->transparent_bg=(bool) graph.attribute("transbg").toInt( &ok );
            if (!ok) return false;
        }
        if (graph.hasAttribute( "xlabel" )) {
            m_params->hasxlabel=(bool) graph.attribute("xlabel").toInt( &ok );
            if (!ok) return false;
        }
        if ( graph.hasAttribute( "xlabel_spacing" ) ) {
            m_params->xlabel_spacing = (short)graph.attribute( "xlabel_spacing" ).toShort( &ok );
            if ( !ok )
                return false;
        }
        if ( graph.hasAttribute( "ylabel_density" ) ) {
            m_params->ylabel_density = (short)graph.attribute( "ylabel_density" ).toShort( &ok );
            if ( !ok )
                return false;
        }
        if (graph.hasAttribute( "line")) {
            m_params->label_line=(bool) graph.attribute("line").toInt( &ok );
            if (!ok) return false;
        }
        if (graph.hasAttribute( "percent")) {
            m_params->percent_labels=(KChartPercentType) graph.attribute("percent").toInt( &ok );
            if (!ok) return false;
        }
        if (graph.hasAttribute("cross")) {
            m_params->cross=(bool) graph.attribute("cross").toInt( &ok );
            if (!ok) return false;
        }
        if (graph.hasAttribute("thumbnail")) {
            m_params->thumbnail=(bool) graph.attribute("thumbnail").toInt( &ok );
            if (!ok) return false;
        }
        if (graph.hasAttribute("thumblabel")) {
            m_params->thumblabel= graph.attribute("thumblabel");
        }
        if (graph.hasAttribute("thumbval")) {
            m_params->thumbval=(bool) graph.attribute("thumbval").toDouble( &ok );
            if (!ok)
                return false;
        }
#endif
    }

#if 0
    QDomElement graphparams = params.namedItem( "graphparams" ).toElement();
    if (!graphparams.isNull()) {
        if (graphparams.hasAttribute( "dept3d" )) {
            m_params->_3d_depth=graphparams.attribute("dept3d").toDouble( &ok );
            if (!ok) return false;
        }
        if (graphparams.hasAttribute( "angle3d" )) {
            m_params->_3d_angle=graphparams.attribute("angle3d").toShort( &ok );
            if (!ok) return false;
        }
        if (graphparams.hasAttribute( "barwidth" )) {
            m_params->bar_width=graphparams.attribute("barwidth").toShort( &ok );
            if (!ok) return false;
        }
        if (graphparams.hasAttribute( "colpie" )) {
            m_params->colPie=graphparams.attribute("colpie").toInt( &ok );
            if (!ok) return false;
        }
        if (graphparams.hasAttribute( "other_threshold" )) {
            m_params->other_threshold=graphparams.attribute("other_threshold").toShort( &ok );
            if (!ok)
                return false;
        }
        if (graphparams.hasAttribute( "offsetCol" )) {
            m_params->offsetCol = graphparams.attribute("offsetCol").toInt( &ok );
            if (!ok)
                return false;
        }
        if (graphparams.hasAttribute( "hard_size" )) {
            m_params->hard_size = (bool)graphparams.attribute("hard_size").toInt( &ok );
            if (!ok)
                return false;
        }
        if (graphparams.hasAttribute( "hard_graphheight" )) {
            m_params->hard_graphheight = graphparams.attribute("hard_graphheight").toInt( &ok );
            if (!ok)
                return false;
        }
        if (graphparams.hasAttribute( "hard_graphwidth" )) {
            m_params->hard_graphwidth = graphparams.attribute("hard_graphwidth").toInt( &ok );
            if (!ok)
                return false;
        }
        if (graphparams.hasAttribute( "hard_xorig" )) {
            m_params->hard_xorig = graphparams.attribute("hard_xorig").toInt( &ok );
            if (!ok)
                return false;
        }
        if (graphparams.hasAttribute( "hard_yorig" )) {
            m_params->hard_yorig = graphparams.attribute("hard_yorig").toInt( &ok );
            if (!ok)
                return false;
        }
        if (graphparams.hasAttribute( "labeldist" )) {
            m_params->label_dist=graphparams.attribute("labeldist").toInt( &ok );
            if (!ok) return false;
        }
    }

    QDomElement graphcolor = params.namedItem( "graphcolor" ).toElement();
    if (!graphcolor.isNull()) {
        if (graphcolor.hasAttribute( "bgcolor" )) {
            m_params->BGColor= QColor( graphcolor.attribute( "bgcolor" ) );
        }
        if (graphcolor.hasAttribute( "gridcolor" )) {
            m_params->GridColor= QColor( graphcolor.attribute( "gridcolor" ) );
        }
        if (graphcolor.hasAttribute( "linecolor" )) {
            m_params->LineColor= QColor( graphcolor.attribute( "linecolor" ) );
        }
        if (graphcolor.hasAttribute( "plotcolor" )) {
            m_params->PlotColor= QColor( graphcolor.attribute( "plotcolor" ) );
        }
        if (graphcolor.hasAttribute( "volcolor" )) {
            m_params->VolColor= QColor( graphcolor.attribute( "volcolor" ) );
        }
        if (graphcolor.hasAttribute( "titlecolor" )) {
            m_params->TitleColor= QColor( graphcolor.attribute( "titlecolor" ) );
        }
        if (graphcolor.hasAttribute( "xtitlecolor" )) {
            m_params->XTitleColor= QColor( graphcolor.attribute( "xtitlecolor" ) );
        }
        if (graphcolor.hasAttribute( "ytitlecolor" )) {
            m_params->YTitleColor= QColor( graphcolor.attribute( "ytitlecolor" ) );
        }
        if (graphcolor.hasAttribute( "ytitle2color" )) {
            m_params->YTitle2Color= QColor( graphcolor.attribute( "ytitle2color" ) );
        }
        if (graphcolor.hasAttribute( "xlabelcolor" )) {
            m_params->XLabelColor= QColor( graphcolor.attribute( "xlabelcolor" ) );
        }
        if (graphcolor.hasAttribute( "ylabelcolor" )) {
            m_params->YLabelColor= QColor( graphcolor.attribute( "ylabelcolor" ) );
        }
        if (graphcolor.hasAttribute( "ylabel2color" )) {
            m_params->YLabel2Color= QColor( graphcolor.attribute( "ylabel2color" ) );
        }
    }

    QDomElement annotation = params.namedItem( "annotation" ).toElement();
    if (!annotation.isNull()) {
        m_params->annotation=new KChartAnnotationType;
        if (annotation.hasAttribute( "color" )) {
            m_params->annotation->color= QColor( annotation.attribute( "color" ) );
        }
        if (annotation.hasAttribute( "point" )) {
            m_params->annotation->point=annotation.attribute("point").toDouble( &ok );
            if (!ok) return false;
        }
    }

    QDomElement note = params.namedItem( "note" ).toElement();
    if ( !note.isNull()) {
        QString t = note.text();
        m_params->annotation->note=t;
    }

    QDomElement scatter = params.namedItem( "scatter" ).toElement();
    if ( !scatter.isNull() ) {
        m_params->scatter = new KChartScatterType;
        if ( scatter.hasAttribute( "point" ) ) {
            m_params->scatter->point = scatter.attribute( "point" ).toDouble( &ok );
            if ( !ok )
                return false;
        }
        if ( scatter.hasAttribute( "val" ) ) {
            m_params->scatter->val = scatter.attribute( "val" ).toDouble( &ok );
            if ( !ok )
                return false;
        }
        if ( scatter.hasAttribute( "width" ) ) {
            m_params->scatter->width = scatter.attribute( "val" ).toUShort( &ok );
            if ( !ok )
                return false;
        }
        if ( scatter.hasAttribute( "color" )) {
            m_params->scatter->color= QColor( scatter.attribute( "color" ) );
        }
        if ( scatter.hasAttribute( "ind" ) ) {
            m_params->scatter->ind = (KChartScatterIndType)scatter.attribute( "ind" ).toInt( &ok );
            if ( !ok )
                return false;
        }
    }

    QDomElement legend = chart.namedItem("legend").toElement();
    if (!legend.isNull()) {
        int number = legend.attribute("number").toInt(&ok);
        if (!ok)  { return false; }
        QDomNode name = legend.firstChild();
        m_params->legend.clear();
        for(int i=0; i<number; i++) {
            if (name.isNull()) {
                kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
                break;
            }
            QDomElement element = name.toElement();
            if ( !element.isNull() && element.tagName() == "name" ) {
                QString t = element.text();
                m_params->legend+=t;
                name = name.nextSibling();
            }
        }
    }

    QDomElement xlbl = chart.namedItem("xlbl").toElement();
    if (!xlbl.isNull()) {
        int number = xlbl.attribute("number").toInt(&ok);
        if (!ok)  { return false; }
        QDomNode label = xlbl.firstChild();
        m_params->xlbl.clear();
        for (int i=0; i<number; i++) {
            if (label.isNull()) {
                kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
                break;
            }
            QDomElement element = label.toElement();
            if ( !element.isNull() && element.tagName() == "label" ) {
                QString t = element.text();
                m_params->xlbl+=t;
                label = label.nextSibling();
            }
        }
    }

    QDomElement backgroundPixmap = chart.namedItem( "backgroundPixmap" ).toElement();
    if ( !backgroundPixmap.isNull() ) {
        if ( backgroundPixmap.hasAttribute( "name" ) )
            m_params->backgroundPixmapName = backgroundPixmap.attribute( "name" );
        if ( backgroundPixmap.hasAttribute( "isDirty" ) ) {
            m_params->backgroundPixmapIsDirty = (bool)backgroundPixmap.attribute( "isDirty" ).toInt( &ok );
            if ( !ok )
                return false;
        }
        if ( backgroundPixmap.hasAttribute( "scaled" ) ) {
            m_params->backgroundPixmapScaled = (bool)backgroundPixmap.attribute( "scaled" ).toInt( &ok );
            if ( !ok )
                return false;
        }
        if ( backgroundPixmap.hasAttribute( "centered" ) ) {
            m_params->backgroundPixmapCentered = (bool)backgroundPixmap.attribute( "centered" ).toInt( &ok );
            if ( !ok )
                return false;
        }
        if ( backgroundPixmap.hasAttribute( "intensity" ) ) {
            m_params->backgroundPixmapIntensity = backgroundPixmap.attribute( "intensity" ).toFloat( &ok );
            if ( !ok )
                return false;
        }
    }

    QDomElement extcolor = chart.namedItem("extcolor").toElement();
    if (!extcolor.isNull()) {
        unsigned int number = extcolor.attribute("number").toInt(&ok);
        if (!ok)  { return false; }
        QDomNode color = extcolor.firstChild();

        for (unsigned int i=0; i<number; i++) {
            if (color.isNull()) {
                kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
                break;
            }
            QDomElement element = color.toElement();
            if ( !element.isNull()) {
                if (element.hasAttribute( "name" )) {
                    m_params->ExtColor.setColor(i,QColor( element.attribute( "name" ) ));
                }
                color = color.nextSibling();
            }
        }
    }

    if ( !m_params->backgroundPixmapName.isNull() ) {
        m_params->backgroundPixmap.load( locate( "wallpaper",
						 m_params->backgroundPixmapName ));
        m_params->backgroundPixmapIsDirty = true;
    }
#endif
    return true;
}



void  KChartPart::slotModified()
{
    kdDebug(35001) << "slotModified called!" << endl;

    setModified(true);
}


bool KChartPart::showEmbedInitDialog(QWidget* /*parent*/)
{
  // Don't show an embed dialog
  return true;
}


}  //KChart namespace

#include "kchart_part.moc"
