kchart

kchart_part.cc

00001 
00006 #include <float.h> // For basic data types characteristics.
00007 
00008 // For debugging
00009 #include <iostream>
00010 using std::cout;
00011 using std::cerr;
00012 
00013 #include "kchart_part.h"
00014 #include "kchart_view.h"
00015 #include "kchart_factory.h"
00016 #include "kchartWizard.h"
00017 #include "kchart_params.h"
00018 #include "kdchart/KDChart.h"
00019 #include "kdchart/KDChartTable.h"
00020 
00021 #include <KoTemplateChooseDia.h>
00022 #include <KoDom.h>
00023 #include <KoXmlNS.h>
00024 #include <KoXmlWriter.h>
00025 #include <KoOasisStore.h>
00026 #include <KoOasisLoadingContext.h>
00027 
00028 #include <kstandarddirs.h>
00029 #include <kglobal.h>
00030 #include <kdebug.h>
00031 
00032 #include <qdom.h>
00033 #include <qtextstream.h>
00034 #include <qbuffer.h>
00035 #include <qpainter.h>
00036 
00037 using namespace std;
00038 
00039 // Some hardcoded data for a chart
00040 
00041 /* ----- set some data ----- */
00042 // float   a[6]  = { 0.5, 0.09, 0.6, 0.85, 0.0, 0.90 },
00043 // b[6]  = { 1.9, 1.3,  0.6, 0.75, 0.1, -2.0 };
00044 /* ----- X labels ----- */
00045 // char    *t[6] = { "Chicago", "New York", "L.A.", "Atlanta", "Paris, MD\n(USA) ", "London" };
00046 /* ----- data set colors (RGB) ----- */
00047 // QColor   sc[2]    = { QColor( 255, 128, 128 ), QColor( 128, 128, 255 ) };
00048 
00049 
00050 namespace KChart
00051 {
00052 
00053 KChartPart::KChartPart( QWidget *parentWidget, const char *widgetName,
00054             QObject* parent, const char* name,
00055             bool singleViewMode )
00056   : KoChart::Part( parentWidget, widgetName, parent, name, singleViewMode ),
00057     m_params( 0 ),
00058     m_parentWidget( parentWidget ),
00059     m_rowLabels(), m_colLabels()
00060 {
00061     kdDebug(35001) << "Constructor started!" << endl;
00062 
00063     setInstance( KChartFactory::global(), false );
00064     setTemplateType( "kchart_template" );
00065 
00066     // Init some members that need it.
00067     {
00068     // Create the chart parameters and let the default be a bar chart
00069     // with 3D looks.
00070     m_params = new KChartParams( this );
00071     m_params->setChartType( KChartParams::Bar );
00072     m_params->setBarChartSubType( KChartParams::BarNormal );
00073     m_params->setThreeDBars( true );
00074 
00075         //Changed this to use columns rather than rows by default
00076         //because I believe that this is the more common format for
00077         //entering data (you can see this looking at the fact that
00078         //most spreadsheet packages allow far more rows than columns)
00079         //-- Robert Knight
00080 
00081     // Handle data in columns by default
00082     m_params->setDataDirection( KChartParams::DataColumns );
00083     }
00084 
00085     (void)new WizardExt( this );
00086     m_bCanChangeValue = true;
00087 
00088     // Display parameters
00089     m_displayData = m_currentData;
00090 
00091     // Set the size to minimal.
00092     initEmpty();
00093 }
00094 
00095 
00096 KChartPart::~KChartPart()
00097 {
00098     //kdDebug(35001) << "Part is going to be destroyed now!!!" << endl;
00099     delete m_params;
00100 }
00101 
00102 
00103 // Reimplement KoDocument::initDoc()
00104 
00105 bool KChartPart::initDoc(InitDocFlags flags, QWidget* parentWidget)
00106 {
00107     // Initialize the parameter set for this chart document
00108 #if 0
00109     kdDebug(35001) << "================================================================" << endl;
00110     kdDebug(35001) << "InitDOC: flags = " << flags << endl;
00111     kdDebug(35001) << "================================================================" << endl;
00112 #endif
00113 
00114     QString f;
00115 
00116     // Embedded documents are initially created like a normal empty
00117     // document.  If this is in KSpread or another program where the
00118     // data is external then the document will be updated later on in
00119     // the creation process anyway.
00120     if (flags == KoDocument::InitDocEmbedded) {
00121     initEmpty();
00122     return true;
00123     }
00124 
00125     // If we are supposed to create a new, empty document, then do so.
00126     if (flags == KoDocument::InitDocEmpty) {
00127     initEmpty();
00128     return true;
00129     }
00130 
00131     KoTemplateChooseDia::ReturnType  ret;
00132     KoTemplateChooseDia::DialogType  dlgtype;
00133 
00134     // If we must create a new document, then only present templates
00135     // to the user, otherwise also present existing documents and
00136     // recent documents.
00137     if (flags == KoDocument::InitDocFileNew )
00138     dlgtype = KoTemplateChooseDia::OnlyTemplates;
00139     else
00140     dlgtype = KoTemplateChooseDia::Everything;
00141     ret = KoTemplateChooseDia::choose( KChartFactory::global(), f,
00142                                        dlgtype, "kchart_template",
00143                        parentWidget );
00144 
00145     if ( ret == KoTemplateChooseDia::File ) {
00146     KURL url( f );
00147     return openURL( url );
00148     }
00149     else if ( ret == KoTemplateChooseDia::Empty ) {
00150     initEmpty();
00151     return true;
00152     }
00153     else if ( ret == KoTemplateChooseDia::Template ) {
00154         //TODO: Activate this for KOffice 1.5/2.0
00155 //      if ( f.endsWith("/templates/chart/.source/BarChart.chrt") ) {
00156 //          generateBarChartTemplate();
00157 //          return true;
00158 //      }
00159         QFileInfo fileInfo( f );
00160         QString fileName( fileInfo.dirPath( true ) + "/" +
00161             fileInfo.baseName() + ".chrt" );
00162 
00163         resetURL();
00164         bool ok = loadNativeFormat( fileName );
00165         if ( !ok )
00166             showLoadingErrorDialog();
00167         setEmpty();
00168         //initConfig();
00169         return ok;
00170     }
00171 
00172     return false;
00173 }
00174 
00175 void KChartPart::initEmpty()
00176 {
00177     initNullChart();
00178 
00179     resetURL();
00180     setEmpty();
00181 }
00182 
00183 
00184 // This method creates the simplest chart imaginable:
00185 // Data size 1x1, empty, no headers
00186 //
00187 void KChartPart::initNullChart()
00188 {
00189     // Fill cells with data if there is none.
00190     //kdDebug(35001) << "Initialize null chart." << endl;
00191 
00192     // Empty data.  Note, we don't use (0,0) or (1,1) for the size
00193     // here, because otherwise KDChart won't draw anything
00194     m_currentData.expand(2, 2);
00195     m_params->setFirstRowAsLabel(false);
00196     m_params->setFirstColAsLabel(false);
00197 
00198     // Fill column and row labels.
00199     m_colLabels << QString("");
00200     m_rowLabels << QString("");
00201 
00202     setChartDefaults();
00203 
00204     m_params->setDrawSolidExcessArrows(true);
00205 }
00206 
00207 
00208 void KChartPart::generateBarChartTemplate()
00209 {
00210     int  col;
00211     int  row;
00212 
00213     kdDebug()<<"KChartPart::initTestChart()\n";
00214 
00215     // Fill cells with data if there is none.
00216     if (m_currentData.rows() == 0) {
00217         //kdDebug(35001) << "Initialize with some data!!!" << endl;
00218         m_currentData.expand( 4, 4 );
00219         m_currentData.setUsedRows( 4 );
00220         m_currentData.setUsedCols( 4 );
00221         for (row = 0; row < 4; row++) {
00222             for (col = 0; col < 4; col++) {
00223                 m_currentData.setCell(row, col,
00224                       static_cast <double> (row + col));
00225 
00226         // Fill column label, but only on the first iteration.
00227         if (row == 0) {
00228             m_colLabels << i18n("Column %1").arg(col + 1);
00229         }
00230             }
00231 
00232         // Fill row label.
00233         m_rowLabels << i18n("Row %1").arg(row + 1);
00234     }
00235     }
00236 
00237     setChartDefaults();
00238     // FIXME: Should this go into setChartDefaults()?
00239     m_params->setDrawSolidExcessArrows(true);
00240 }
00241 
00242 
00243 KoView* KChartPart::createViewInstance( QWidget* parent, const char* name )
00244 {
00245     return new KChartView( this, parent, name );
00246 }
00247 
00248 
00249 // ================================================================
00250 //                              Painting
00251 
00252 
00253 void KChartPart::paintContent( QPainter& painter, const QRect& rect,
00254                    bool /*transparent*/,
00255                    double /*zoomX*/, double /*zoomY*/ )
00256 {
00257     int  numDatasets;
00258 
00259     // If params is 0, initDoc() has not been called.
00260     Q_ASSERT( m_params != 0 );
00261 
00262     KDChartAxisParams  xAxisParms;
00263     xAxisParms = m_params->axisParams( KDChartAxisParams::AxisPosBottom );
00264 
00265     // Handle data in rows or columns.
00266     //
00267     // This means getting row or column headers from the document and
00268     // set them as X axis labels or legend according to the current
00269     // setting.  Also, transpose the data if it should be displayed in
00270     // columns instead of in rows.
00271 
00272 
00273     // Create the displayData table.
00274     numDatasets = createDisplayData();
00275 
00276     // Create and set the axis labels and legend.
00277     QStringList  longLabels;
00278     QStringList  shortLabels;
00279     createLabelsAndLegend(longLabels, shortLabels);
00280 
00281     // Set the x axis labels.
00282     xAxisParms.setAxisLabelStringLists( &longLabels, &shortLabels );
00283     m_params->setAxisParams(KDChartAxisParams::AxisPosBottom, xAxisParms);
00284 
00285 
00286     // Handle some types or subtypes of charts specially, notably:
00287     //  - Bar charts with lines in them
00288 
00289     if ( m_params->chartType() == KChartParams::Bar) {
00290     if ( m_params->barNumLines() > 0 ) {
00291 
00292         // If this is a bar chart and the user wants a few lines in
00293         // it, we need to create an additional chart in the same
00294         // drawing area.
00295 
00296         // Specify that we want to have an additional chart.
00297         m_params->setAdditionalChartType( KDChartParams::Line );
00298 
00299         const int numBarDatasets = numDatasets - m_params->barNumLines();
00300 
00301         // Assign the datasets to the charts: DataEntry, from, to, chart#
00302         m_params->setChartSourceMode( KDChartParams::DataEntry,
00303                       0, numBarDatasets - 1,
00304                       0 ); // The bar chart
00305         m_params->setChartSourceMode( KDChartParams::DataEntry,
00306                       numBarDatasets, numDatasets - 1,
00307                       1 ); // The line chart
00308     }
00309     else {
00310         // Otherwise we don't want any extra chart.
00311         m_params->setAdditionalChartType( KDChartParams::NoType );
00312     }
00313     }
00314 
00315     // Ok, we have now created a data set for display, and params with
00316     // suitable legends and axis labels.  Now start the real painting.
00317 
00318     // Handle transparency.
00319     // Wrong: this flickers; better do this as part of the double-buffering.
00320     //if ( !transparent )
00321     //    painter.eraseRect( rect );
00322 
00323     // ## TODO: support zooming
00324 
00325     // Double-buffering
00326     if ( m_bufferPixmap.width() < rect.width()
00327      || m_bufferPixmap.height() < rect.height() )
00328     {
00329         m_bufferPixmap.resize( rect.size() );
00330     }
00331 
00332     QPainter bufferPainter( &m_bufferPixmap );
00333 
00334     // We only need to draw the document rectangle "rect".
00335     KDChart::paint( &bufferPainter, m_params, &m_displayData, 0, &rect );
00336 
00337     // This is always the empty rect...
00338     // Shouldn't creating a QPainter in a paintEvent set up clipping automatically?
00339     // I thought it did (DF)
00340     //const QRect clipRect = painter.clipRegion().boundingRect();
00341     //painter.drawPixmap( clipRect.topLeft(), m_bufferPixmap, clipRect );
00342 
00343     painter.drawPixmap( 0, 0, m_bufferPixmap );
00344 }
00345 
00346 
00347 // Create the data table m_displayData from m_currentData, taking into
00348 // account if the first row or line contains headers.  The chart type
00349 // HiLo demands special handling.
00350 //
00351 // Return number of datasets.
00352 //
00353 // Note: While the current KD Chart 1.1.3 version is still expecting data
00354 //       to be in rows, the upcoming KD Chart 2.0 release will be using
00355 //       data in columns instead, to it will be matching KSpread's way.
00356 //       -khz, 2005-11-15
00357 //
00358 // FIXME: Rewrite so that we only copy data when necessary.
00359 //        On the other hand, the next version of KDChart is able to
00360 //        get data directly without storing it into a KDChartData
00361 //        class first, so we might never need to.
00362 //
00363 int  KChartPart::createDisplayData()
00364 {
00365     int  rowOffset   = 0;
00366     int  colOffset   = 0;
00367     int  numDatasets = 0;
00368 
00369     if ( !canChangeValue() ) {
00370     if ( m_params->firstRowAsLabel() )
00371         rowOffset++;
00372     if ( m_params->firstColAsLabel() )
00373         colOffset++;
00374     }
00375 
00376     // After this sequence, m_DisplayData contains the data in the
00377     // correct transposition, and the X axis and the legend contain
00378     // the correct labels.
00379     QVariant  value1;
00380     QVariant  value2;
00381     int       prop;
00382     if (m_params->dataDirection() == KChartParams::DataRows) {
00383     // Data is handled in rows.  This is the way KDChart works also.
00384 
00385     numDatasets = m_currentData.usedRows() - rowOffset;
00386     m_displayData.expand( numDatasets,
00387                   m_currentData.usedCols() - colOffset );
00388 
00389     // Remove the first row and/or col if they are used for headers.
00390     for (uint row = rowOffset; row < m_currentData.usedRows(); row++) {
00391         for (uint col = colOffset; col < m_currentData.usedCols(); col++) {
00392         if ( m_currentData.cellContent( row, col,
00393                         value1, value2, prop ) ) {
00394             m_displayData.setCell(row - rowOffset, col - colOffset,
00395                       value1, value2);
00396             m_displayData.setProp(row - rowOffset, col - colOffset,
00397                       prop);
00398                 }
00399         }
00400     }
00401     }
00402     else {
00403     // Data is handled in columns.  We will have to transpose
00404     // everything since KDChart wants its data in rows.
00405 
00406     // Resize displayData so that the transposed data has room.
00407     numDatasets = m_currentData.usedCols() - colOffset;
00408     m_displayData.expand( numDatasets,
00409                   m_currentData.usedRows() - rowOffset );
00410 
00411     // Copy data and transpose it.
00412     for (uint row = colOffset; row < m_currentData.usedCols(); row++) {
00413         for (uint col = rowOffset; col < m_currentData.usedRows(); col++) {
00414                 if ( m_currentData.cellContent( col, row,
00415                         value1, value2, prop ) ) {
00416             m_displayData.setCell(row - colOffset, col - rowOffset,
00417                       value1, value2);
00418             m_displayData.setProp(row - colOffset, col - rowOffset,
00419                       prop);
00420                 }
00421         }
00422     }
00423     }
00424 
00425     // If this is a HiLo chart, we need to manually create the correct
00426     // values.  This is not done by KDChart.
00427     //
00428     // Here we don't need to transpose, since we can start from the
00429     // newly generated displayData.
00430     if (m_params->chartType() == KChartParams::HiLo) {
00431     KDChartTableData  tmpData = m_displayData;
00432 
00433     // Calculate the min, max, open and close values for each row.
00434     m_displayData.expand(tmpData.usedRows(), 4);
00435     for (uint row = 0; row < tmpData.usedRows(); row++) {
00436         double  minVal   = DBL_MAX;
00437         double  maxVal   = -DBL_MAX;
00438 
00439         // Calculate min and max for this row.
00440         //
00441         // Note that we have already taken care of different data
00442         // directions above.
00443         for (uint col = 0; col < tmpData.usedCols(); col++) {
00444         double  data = tmpData.cellVal(row, col).toDouble();
00445 
00446         if (data < minVal)
00447             minVal = data;
00448         if (data > maxVal)
00449             maxVal = data;
00450         }
00451         m_displayData.setCell(row, 0, minVal); // min
00452         m_displayData.setCell(row, 1, maxVal); // max
00453         m_displayData.setCell(row, 2, tmpData.cellVal(row, 0).toDouble());   // open
00454         m_displayData.setCell(row, 3,                          // close
00455                   tmpData.cellVal(row, tmpData.usedCols() - 1).toDouble());
00456     }
00457     }
00458 
00459     return numDatasets;
00460 }
00461 
00462 
00463 void KChartPart::createLabelsAndLegend( QStringList  &longLabels,
00464                     QStringList  &shortLabels )
00465 {
00466     longLabels.clear();
00467     shortLabels.clear();
00468 
00469     const uint dataColumnCount  = m_currentData.cols();
00470     const uint dataRowCount     = m_currentData.rows();
00471     const uint columnLabelCount = m_colLabels.count();
00472     const uint rowLabelCount    = m_rowLabels.count();
00473 
00474     // Handle HiLo charts separately.
00475     if (m_params->chartType() == KChartParams::HiLo) {
00476 
00477       // FIXME: In a HiLo chart, the Legend should be the same as the
00478       //        labels on the X Axis.  Should we disable one of them?
00479 
00480     // Set the correct X axis labels and legend.
00481     longLabels.clear();
00482     shortLabels.clear();
00483     if (m_params->dataDirection() == KChartParams::DataRows) {
00484 
00485         // If data are in rows, then the X axis labels should be
00486         // taken from the row headers.
00487         for ( uint row = 0; row < dataRowCount ; row++ ) {
00488 
00489                 QString label = (row < rowLabelCount) ? m_rowLabels[row] : QString::null;
00490 
00491                 longLabels  << label;
00492         shortLabels << label.left( 3 );
00493         }
00494     }
00495     else {
00496         // If data are in columns, then the X axis labels should
00497         // be taken from the column headers.
00498         for ( uint col = 0; col < dataColumnCount; col++ ) {
00499 
00500                 QString label = (col < columnLabelCount) ? m_colLabels[col] : QString::null;
00501 
00502                 longLabels  << m_colLabels[col];
00503         shortLabels << m_colLabels[col].left( 3 );
00504         }
00505     }
00506     }
00507     else if (m_params->dataDirection() == KChartParams::DataRows) {
00508     // Data is handled in rows.  This is the way KDChart works also.
00509 
00510     // Set X axis labels from column headers.
00511     for ( uint col = 0; col < dataColumnCount; col++ ) {
00512 
00513             QString label = (col < columnLabelCount) ? m_colLabels[col] : QString::null;
00514 
00515             longLabels  << label;
00516         shortLabels << label.left( 3 );
00517     }
00518 
00519     // Set legend from row headers.
00520         for ( uint row = 0; row < dataRowCount; row++ ) {
00521             QString label = (row < rowLabelCount) ? m_rowLabels[row] : QString::null;
00522 
00523             m_params->setLegendText( row, label );
00524         }
00525     }
00526     else {
00527     // Data is handled in columns.
00528 
00529     // Set X axis labels from row headers.
00530     for ( uint row = 0; row < dataRowCount; row++ ) {
00531 
00532             QString label = (row < rowLabelCount) ? m_rowLabels[row] : QString::null;
00533 
00534             longLabels  << label;
00535         shortLabels << label.left( 3 );
00536     }
00537 
00538     // Set legend from column headers.
00539         for ( uint col = 0; col < dataColumnCount ; col++ ) {
00540             QString label = (col < columnLabelCount) ? m_colLabels[col] : QString::null;
00541 
00542             m_params->setLegendText( col, label );
00543         }
00544     }
00545 }
00546 
00547 
00548 
00549 // ================================================================
00550 
00551 
00552 void KChartPart::analyzeHeaders()
00553 {
00554 #if 0
00555     analyzeHeaders( m_currentData );
00556 #else
00557     doSetData( m_currentData,
00558            m_params->firstRowAsLabel(), m_params->firstColAsLabel());
00559 #endif
00560 }
00561 
00562 
00563 // This function sets the data from an external source.  It is called,
00564 // for instance, when the chart is initialized from a spreadsheet in
00565 // KSpread.
00566 //
00567 void KChartPart::analyzeHeaders( const KDChartTableData& data )
00568 {
00569     // FIXME(khz): replace this when automatic string detection works in KDChart
00570     // Does the top/left cell contain a string?
00571     bool isStringTopLeft = (data.cellVal( 0, 0 ).type() == QVariant::String);
00572 
00573     // Does the first row (without first cell) contain only strings?
00574     bool isStringFirstRow = true;
00575     for ( uint col = 1; isStringFirstRow && col < data.cols(); col++ ) {
00576         isStringFirstRow = (data.cellVal( 0, col ).type() == QVariant::String);
00577     }
00578 
00579     // Just in case, we only have 1 row, we never use it for label text.
00580     // This prevents a crash.
00581     //
00582     // FIXME: Wonder if this is still true for KDChart 1.1.3 / iw
00583     //        Disabling...
00584 #if 1
00585     if ( data.rows() == 1 )
00586         isStringFirstRow = false;
00587 #endif
00588 
00589     // Does the first column (without first cell) contain only strings?
00590     bool isStringFirstCol = true;
00591     for ( uint row = 1; isStringFirstCol && row < data.rows(); row++ ) {
00592         isStringFirstCol = (data.cellVal( row, 0 ).type() == QVariant::String);
00593     }
00594 
00595     // Just in case, we only have 1 column, we never use it for axis
00596     // label text => prevents crash.
00597 #if 1
00598     if ( data.cols() == 1 )
00599         isStringFirstRow = FALSE;
00600 #endif
00601 
00602     bool hasColHeader = false;
00603     bool hasRowHeader = false;
00604 
00605     // Let's check if we have a full axis label text column
00606     if ( isStringFirstCol && isStringTopLeft
00607      || isStringFirstCol && isStringFirstRow )
00608         hasColHeader = true;
00609 
00610     // Let's check if we have a full label text row.
00611     if ( isStringFirstRow && isStringTopLeft
00612      || isStringFirstCol && isStringFirstRow )
00613         hasRowHeader = true;
00614 
00615     m_params->setFirstRowAsLabel( hasRowHeader );
00616     m_params->setFirstColAsLabel( hasColHeader );
00617 
00618     doSetData(data, hasRowHeader, hasColHeader);
00619 }
00620 
00621 
00622 
00623 void KChartPart::doSetData( const KDChartTableData&  data,
00624                 bool  firstRowHeader,
00625                 bool  firstColHeader )
00626 {
00627     uint  rowStart = 0;
00628     uint  colStart = 0;
00629     uint  col;
00630     uint  row;
00631 
00632     // From this point, we know that the labels and legend are going
00633     // to be taken from the data if firstRowHeader or firstColheader
00634     // is true.
00635 
00636     if (firstRowHeader)
00637         rowStart = 1;
00638     if (firstColHeader)
00639         colStart = 1;
00640 
00641     // Generate m_rowlabels from the column headers if applicable.
00642     m_rowLabels.clear();
00643     if ( firstColHeader ) {
00644     for( row = rowStart; row < data.rows(); row++ ) {
00645         m_rowLabels << data.cellVal( row, 0 ).toString();
00646     }
00647     }
00648     else {
00649     for( row = rowStart; row < data.rows(); row++ )
00650         m_rowLabels << "";
00651 
00652     // FIXME: Check what this does, and if we don't have to check
00653     //        the data order (rows / cols).
00654     m_params->setLegendSource( KDChartParams::LegendAutomatic );
00655     }
00656 
00657     // Generate X labels from the row headers if applicable
00658     m_colLabels.clear();
00659     if ( firstRowHeader ) {
00660         for( col = colStart; col < data.cols(); col++ ) {
00661         m_colLabels << data.cellVal( 0, col ).toString();
00662     }
00663     }
00664     else {
00665     for( col = colStart; col < data.cols(); col++ )
00666         m_colLabels << "";
00667     }
00668 
00669     // Doesn't hurt if data == m_currentData, but necessary if not.
00670     m_currentData = data;
00671 
00672     //setChartDefaults();
00673 
00674     emit docChanged();
00675 }
00676 
00677 
00678 void KChartPart::resizeData( int rows, int cols )
00679 {
00680     m_currentData.expand( rows, cols );
00681     m_currentData.setUsedRows( rows );
00682     m_currentData.setUsedCols( cols );
00683 }
00684 
00685 
00686 void KChartPart::setCellData( int row, int column, const QVariant &val)
00687 {
00688     m_currentData.setCell( row, column, val );
00689 }
00690 
00691 
00692 bool KChartPart::showWizard( QString &dataArea )
00693 {
00694     KChartWizard  *wizard = new KChartWizard( this, m_parentWidget, "wizard" );
00695 
00696     connect( wizard, SIGNAL(finished()), this, SLOT(slotModified()) );
00697 
00698     wizard->setDataArea( dataArea );
00699 
00700     bool  ret = wizard->exec();
00701 
00702     delete wizard;
00703     return ret;
00704 }
00705 
00706 
00707 void KChartPart::initLabelAndLegend()
00708 {
00709     // Labels and legends are automatically initialized to reasonable
00710     // default values in KDChart
00711 }
00712 
00713 
00714 // Set up some values for the chart Axis, that are not well chosen by
00715 // default by KDChart.
00716 //
00717 
00718 void KChartPart::setChartDefaults()
00719 {
00720   //
00721   // Settings for the Y axis.
00722   //
00723   KDChartAxisParams  yAxis;
00724   yAxis = m_params->axisParams( KDChartAxisParams::AxisPosLeft );
00725 
00726   // decimal symbol and thousands separator
00727   yAxis.setAxisLabelsRadix( KGlobal::locale()->decimalSymbol(),
00728                 KGlobal::locale()->thousandsSeparator() );
00729 
00730   m_params->setAxisParams( KDChartAxisParams::AxisPosLeft, yAxis );
00731 
00732   //
00733   // Settings for the X axis.
00734   //
00735   KDChartAxisParams  xAxis;
00736   xAxis = m_params->axisParams( KDChartAxisParams::AxisPosBottom );
00737 
00738   // These two shouldn't be necessary to set.
00739   xAxis.setAxisFirstLabelText();
00740   xAxis.setAxisLastLabelText();
00741 
00742   m_params->setAxisParams( KDChartAxisParams::AxisPosBottom, xAxis );
00743 
00744   // Other parameters for various things.
00745   m_params->setLineColor();
00746 
00747   // Setting the background layer.
00748   KDFrame frame;
00749   frame.setBackground( QBrush( QColor( 230, 222, 222 ) ) );
00750   m_params->setFrame( KDChartEnums::AreaInnermost, frame, 0, 0, 0, 0 );
00751 }
00752 
00753 
00754 // ================================================================
00755 //                     Loading and Storing
00756 
00757 
00758 // ----------------------------------------------------------------
00759 //                 Save and Load program configuration
00760 
00761 
00762 
00763 void KChartPart::loadConfig( KConfig *conf )
00764 {
00765     conf->setGroup("ChartParameters");
00766 
00767     // TODO: the fonts
00768     // PENDING(kalle) Put the applicable ones of these back in
00769     //   QFont tempfont;
00770     //   tempfont = conf->readFontEntry("titlefont", &titlefont);
00771     //   setTitleFont(tempfont);
00772     //   tempfont = conf->readFontEntry("ytitlefont", &ytitlefont);
00773     //   setYTitleFont(tempfont);
00774     //   tempfont = conf->readFontEntry("xtitlefont", &xtitlefont);
00775     //   setXTitleFont(tempfont);
00776     //   tempfont = conf->readFontEntry("yaxisfont", &yaxisfont);
00777     //   setYAxisFont(tempfont);
00778     //   tempfont = conf->readFontEntry("xaxisfont", &xaxisfont);
00779     //   setXAxisFont(tempfont);
00780     //   tempfont = conf->readFontEntry("labelfont", &labelfont);
00781     //   setLabelFont(tempfont);
00782     //   tempfont = conf->readFontEntry("annotationfont", &annotationfont);
00783     //   setAnnotationFont(tempfont);
00784 
00785     //   ylabel_fmt = conf->readEntry("ylabel_fmt", ylabel_fmt );
00786     //   ylabel2_fmt = conf->readEntry("ylabel2_fmt", ylabel2_fmt);
00787     //   xlabel_spacing = conf->readNumEntry("xlabel_spacing");
00788     //   ylabel_density = conf->readNumEntry("ylabel_density", ylabel_density);
00789     //   requested_ymin = conf->readDoubleNumEntry("requested_ymin", requested_ymin);
00790     //   requested_ymax = conf->readDoubleNumEntry("requested_ymax", requested_ymax );
00791     //   requested_yinterval = conf->readDoubleNumEntry("requested_yinterval",
00792     //                     requested_yinterval);
00793     //   shelf = conf->readBoolEntry("shelf", shelf);
00794     //   grid = conf->readBoolEntry("grid", grid);
00795     //   xaxis = conf->readBoolEntry("xaxis", xaxis);
00796     //   yaxis = conf->readBoolEntry("yaxis", yaxis);
00797     //   yaxis2 = conf->readBoolEntry("yaxis2", yaxis);
00798     //   llabel = conf->readBoolEntry("llabel", llabel);
00799     //   yval_style = conf->readNumEntry("yval_style", yval_style);
00800     //   stack_type = (KChartStackType)conf->readNumEntry("stack_type", stack_type);
00801     m_params->setLineMarker(conf->readBoolEntry("lineMarker",
00802                         m_params->lineMarker()));
00803     m_params->setThreeDBarDepth( conf->readDoubleNumEntry("_3d_depth",
00804                               m_params->threeDBarDepth() ) );
00805     m_params->setThreeDBarAngle( conf->readNumEntry( "_3d_angle",
00806                              m_params->threeDBarAngle() ) );
00807 
00808     KDChartAxisParams  leftparams;
00809     leftparams = m_params->axisParams( KDChartAxisParams::AxisPosLeft );
00810     KDChartAxisParams  rightparams;
00811     rightparams = m_params->axisParams( KDChartAxisParams::AxisPosRight );
00812     KDChartAxisParams  bottomparams;
00813     bottomparams = m_params->axisParams( KDChartAxisParams::AxisPosBottom );
00814 
00815     bottomparams.setAxisLineColor( conf->readColorEntry( "XTitleColor", 0 ) );
00816     leftparams.setAxisLineColor( conf->readColorEntry( "YTitleColor", 0 ) );
00817     rightparams.setAxisLineColor( conf->readColorEntry( "YTitle2Color", 0 ) );
00818     bottomparams.setAxisLabelsColor( conf->readColorEntry( "XLabelColor", 0 ) );
00819     leftparams.setAxisLabelsColor( conf->readColorEntry( "YLabelColor", 0 ) );
00820     rightparams.setAxisLabelsColor( conf->readColorEntry( "YLabel2Color", 0 ) );
00821     leftparams.setAxisGridColor( conf->readColorEntry( "GridColor", 0 ) );
00822     m_params->setOutlineDataColor( conf->readColorEntry( "LineColor", 0 ) );
00823     m_params->setAxisParams( KDChartAxisParams::AxisPosLeft,
00824                             leftparams );
00825     m_params->setAxisParams( KDChartAxisParams::AxisPosRight,
00826                             rightparams );
00827     m_params->setAxisParams( KDChartAxisParams::AxisPosBottom,
00828                             bottomparams );
00829 
00830     //   hlc_style = (KChartHLCStyle)conf->readNumEntry("hlc_style", hlc_style);
00831     //   hlc_cap_width = conf->readNumEntry("hlc_cap_width", hlc_cap_width);
00832     //   // TODO: Annotation font
00833     //   num_scatter_pts = conf->readNumEntry("num_scatter_pts", num_scatter_pts);
00834     //   // TODO: Scatter type
00835     //   thumbnail = conf->readBoolEntry("thumbnail", thumbnail);
00836     //   thumblabel = conf->readEntry("thumblabel", thumblabel);
00837     //   border = conf->readBoolEntry("border", border);
00838     //   BGColor = conf->readColorEntry("BGColor", &BGColor);
00839     //   PlotColor = conf->readColorEntry("PlotColor", &PlotColor);
00840     //   VolColor = conf->readColorEntry("VolColor", &VolColor);
00841     //   EdgeColor = conf->readColorEntry("EdgeColor", &EdgeColor);
00842     //   loadColorArray(conf, &SetColor, "SetColor");
00843     //   loadColorArray(conf, &ExtColor, "ExtColor");
00844     //   loadColorArray(conf, &ExtVolColor, "ExtVolColor");
00845     //   transparent_bg = conf->readBoolEntry("transparent_bg", transparent_bg);
00846     //   // TODO: explode, missing
00847     //   percent_labels = (KChartPercentType)conf->readNumEntry("percent_labels",
00848     //                           percent_labels);
00849     //   label_dist = conf->readNumEntry("label_dist", label_dist);
00850     //   label_line = conf->readBoolEntry("label_line", label_line);
00851     m_params->setChartType( (KChartParams::ChartType)conf->readNumEntry( "type", m_params->chartType() ) );
00852     //   other_threshold = conf->readNumEntry("other_threshold", other_threshold);
00853 
00854     //   backgroundPixmapName = conf->readPathEntry( "backgroundPixmapName" );
00855     //   if( !backgroundPixmapName.isNull() ) {
00856     //     backgroundPixmap.load( locate( "wallpaper", backgroundPixmapName ));
00857     //     backgroundPixmapIsDirty = true;
00858     //   } else
00859     //     backgroundPixmapIsDirty = false;
00860     //   backgroundPixmapScaled = conf->readBoolEntry( "backgroundPixmapScaled", true );
00861     //   backgroundPixmapCentered = conf->readBoolEntry( "backgroundPixmapCentered", true );
00862     //   backgroundPixmapIntensity = conf->readDoubleNumEntry( "backgroundPixmapIntensity", 0.25 );
00863 }
00864 
00865 
00866 void KChartPart::defaultConfig(  )
00867 {
00868     delete m_params;
00869     m_params = new KChartParams( this );
00870     setChartDefaults();
00871 }
00872 
00873 
00874 void KChartPart::saveConfig( KConfig *conf )
00875 {
00876     conf->setGroup("ChartParameters");
00877 
00878     // PENDING(kalle) Put some of these back in
00879     // the fonts
00880     //   conf->writeEntry("titlefont", titlefont);
00881     //   conf->writeEntry("ytitlefont", ytitlefont);
00882     //   conf->writeEntry("xtitlefont", xtitlefont);
00883     //   conf->writeEntry("yaxisfont", yaxisfont);
00884     //   conf->writeEntry("xaxisfont", xaxisfont);
00885     //   conf->writeEntry("labelfont", labelfont);
00886 
00887     //   conf->writeEntry("ylabel_fmt", ylabel_fmt);
00888     //   conf->writeEntry("ylabel2_fmt", ylabel2_fmt);
00889     //   conf->writeEntry("xlabel_spacing", xlabel_spacing);
00890     //   conf->writeEntry("ylabel_density", ylabel_density);
00891     //   conf->writeEntry("requested_ymin", requested_ymin);
00892     //   conf->writeEntry("requested_ymax", requested_ymax);
00893     //   conf->writeEntry("requested_yinterval", requested_yinterval);
00894 
00895     //   conf->writeEntry("shelf", shelf);
00896     //   conf->writeEntry("grid", grid );
00897     //   conf->writeEntry("xaxis", xaxis);
00898     //   conf->writeEntry("yaxis", yaxis);
00899     //   conf->writeEntry("yaxis2", yaxis2);
00900     //   conf->writeEntry("llabel", llabel);
00901     //   conf->writeEntry("yval_style", yval_style );
00902     //   conf->writeEntry("stack_type", (int)stack_type);
00903 
00904     conf->writeEntry( "_3d_depth", m_params->threeDBarDepth() );
00905     conf->writeEntry( "_3d_angle", m_params->threeDBarAngle() );
00906 
00907     KDChartAxisParams leftparams;
00908     leftparams   = m_params->axisParams( KDChartAxisParams::AxisPosLeft );
00909     KDChartAxisParams rightparams;
00910     rightparams  = m_params->axisParams( KDChartAxisParams::AxisPosRight );
00911     KDChartAxisParams bottomparams;
00912     bottomparams = m_params->axisParams( KDChartAxisParams::AxisPosBottom );
00913     conf->writeEntry( "LineColor",    m_params->outlineDataColor() );
00914     conf->writeEntry( "XTitleColor",  bottomparams.axisLineColor() );
00915     conf->writeEntry( "YTitleColor",  leftparams.axisLineColor() );
00916     conf->writeEntry( "YTitle2Color", rightparams.axisLineColor() );
00917     conf->writeEntry( "XLabelColor",  bottomparams.axisLabelsColor() );
00918     conf->writeEntry( "YLabelColor",  leftparams.axisLabelsColor() );
00919     conf->writeEntry( "YLabel2Color", rightparams.axisLabelsColor() );
00920     conf->writeEntry( "GridColor",    leftparams.axisGridColor() );
00921 
00922     //   conf->writeEntry("hlc_style", (int)hlc_style);
00923     //   conf->writeEntry("hlc_cap_width", hlc_cap_width );
00924     //   // TODO: Annotation type!!!
00925     //   conf->writeEntry("annotationfont", annotationfont);
00926     //   conf->writeEntry("num_scatter_pts", num_scatter_pts);
00927     //   // TODO: Scatter type!!!
00928     //   conf->writeEntry("thumbnail", thumbnail);
00929     //   conf->writeEntry("thumblabel", thumblabel);
00930     //   conf->writeEntry("thumbval", thumbval);
00931     //   conf->writeEntry("border", border);
00932     //   conf->writeEntry("BGColor", BGColor);
00933     //   conf->writeEntry("PlotColor", PlotColor);
00934     //   conf->writeEntry("VolColor", VolColor);
00935     //   conf->writeEntry("EdgeColor", EdgeColor);
00936     //   saveColorArray(conf, &SetColor, "SetColor");
00937     //   saveColorArray(conf, &ExtColor, "ExtColor");
00938     //   saveColorArray(conf, &ExtVolColor, "ExtVolColor");
00939 
00940 
00941     //   conf->writeEntry("transparent_bg", transparent_bg);
00942     //   // TODO: explode, missing
00943     //   conf->writeEntry("percent_labels",(int) percent_labels );
00944     //   conf->writeEntry("label_dist", label_dist);
00945     //   conf->writeEntry("label_line", label_line);
00946     conf->writeEntry( "type", (int) m_params->chartType() );
00947     //   conf->writeEntry("other_threshold", other_threshold);
00948 
00949     // background pixmap stuff
00950     //   if( !backgroundPixmapName.isNull() )
00951     //  conf->writePathEntry( "backgroundPixmapName", backgroundPixmapName );
00952     //   conf->writeEntry( "backgroundPixmapIsDirty", backgroundPixmapIsDirty );
00953     //   conf->writeEntry( "backgroundPixmapScaled", backgroundPixmapScaled );
00954     //   conf->writeEntry( "backgroundPixmapCentered", backgroundPixmapCentered );
00955     //   conf->writeEntry( "backgroundPixmapIntensity", backgroundPixmapIntensity );
00956     conf->writeEntry( "lineMarker", (int) m_params->lineMarker());
00957 }
00958 
00959 
00960 // ----------------------------------------------------------------
00961 //              Save and Load OpenDocument file format
00962 
00963 
00964 bool KChartPart::loadOasis( const QDomDocument& doc,
00965                 KoOasisStyles&      oasisStyles,
00966                 const QDomDocument& /*settings*/,
00967                 KoStore            *store )
00968 {
00969     kdDebug(35001) << "kchart loadOasis called" << endl;
00970 
00971     // Set some sensible defaults.
00972     setChartDefaults();
00973 
00974     QDomElement  content = doc.documentElement();
00975     QDomElement  bodyElem ( KoDom::namedItemNS( content,
00976                         KoXmlNS::office, "body" ) );
00977     if ( bodyElem.isNull() ) {
00978         kdError(32001) << "No office:body found!" << endl;
00979         setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No office:body tag found." ) );
00980         return false;
00981     }
00982 
00983     // Get the office:chart element.
00984     QDomElement officeChartElem = KoDom::namedItemNS( bodyElem,
00985                               KoXmlNS::office, "chart" );
00986     if ( officeChartElem.isNull() ) {
00987         kdError(32001) << "No office:chart found!" << endl;
00988         QDomElement  childElem;
00989         QString      localName;
00990         forEachElement( childElem, bodyElem ) {
00991             localName = childElem.localName();
00992         }
00993 
00994         if ( localName.isEmpty() )
00995             setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No tag found inside office:body." ) );
00996         else
00997             setErrorMessage( i18n( "This document is not a chart, but %1. Please try opening it with the appropriate application." ).arg( KoDocument::tagNameToDocumentType( localName ) ) );
00998 
00999         return false;
01000     }
01001 
01002     QDomElement chartElem = KoDom::namedItemNS( officeChartElem,
01003                         KoXmlNS::chart, "chart" );
01004     if ( chartElem.isNull() ) {
01005         setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No chart:chart tag found." ) );
01006         return false;
01007     }
01008 
01009     // Get the loading context and stylestack from the styles.
01010     KoOasisLoadingContext  loadingContext( this, oasisStyles, store );
01011     //KoStyleStack          &styleStack = loadingContext.styleStack();
01012 
01013 #if 0  // Example code!!
01014     // load chart properties into the stylestack.
01015     styleStack.save();
01016     styleStack.setTypeProperties( "chart" ); // load chart properties
01017     loadingContext.fillStyleStack( chartElem, KoXmlNS::chart, "style-name" );
01018 
01019     const QString fillColor = styleStack.attributeNS( KoXmlNS::draw, "fill-color" );
01020     kdDebug() << "fillColor=" << fillColor << endl;
01021 
01022     styleStack.restore();
01023 #endif
01024 
01025     // Load chart parameters, most of these are stored in the
01026     // chart:plot-area element within chart:chart.
01027     QString  errorMessage;
01028     bool     ok = m_params->loadOasis( chartElem, loadingContext, errorMessage,
01029                        store);
01030     if ( !ok ) {
01031         setErrorMessage( errorMessage );
01032         return false;
01033     }
01034 
01035     // TODO Load data direction (see loadAuxiliary)
01036 
01037     // Load the data table.
01038     QDomElement tableElem = KoDom::namedItemNS( chartElem,
01039                         KoXmlNS::table, "table" );
01040     if ( !tableElem.isNull() ) {
01041         ok = loadOasisData( tableElem );
01042         if ( !ok )
01043             return false; // TODO setErrorMessage
01044     }
01045 
01046     return true;
01047 }
01048 
01049 
01050 bool KChartPart::loadOasisData( const QDomElement& tableElem )
01051 {
01052     int          numberHeaderColumns = 0;
01053     QDomElement  tableHeaderColumns = KoDom::namedItemNS( tableElem,
01054                               KoXmlNS::table,
01055                               "table-header-columns" );
01056 
01057     QDomElement  elem;
01058     forEachElement( elem, tableHeaderColumns ) {
01059         if ( elem.localName() == "table-column" ) {
01060             int repeated = elem.attributeNS( KoXmlNS::table, "number-columns-repeated", QString::null ).toInt();
01061             numberHeaderColumns += QMAX( 1, repeated );
01062         }
01063     }
01064 
01065     // With 0 you get no titles, and with more than 1 we ignore the others.
01066     Q_ASSERT( numberHeaderColumns == 1 );
01067 
01068     int numberDataColumns = 0;
01069     QDomElement tableColumns = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-columns" );
01070     forEachElement( elem, tableColumns ) {
01071         if ( elem.localName() == "table-column" ) {
01072             int repeated = elem.attributeNS( KoXmlNS::table, "number-columns-repeated", QString::null ).toInt();
01073             numberDataColumns += QMAX( 1, repeated );
01074         }
01075     }
01076 
01077     // Parse table-header-rows for the column names.
01078     m_colLabels.clear();
01079     QDomElement tableHeaderRows = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-header-rows" );
01080     if ( tableHeaderRows.isNull() )
01081         kdWarning(35001) << "No table-header-rows element found!" << endl;
01082     QDomElement tableHeaderRow = KoDom::namedItemNS( tableHeaderRows, KoXmlNS::table, "table-row" );
01083     if ( tableHeaderRow.isNull() )
01084         kdWarning(35001) << "No table-row inside table-header-rows!" << endl;
01085 
01086     int cellNum = 0;
01087     forEachElement( elem, tableHeaderRow ) {
01088         if ( elem.localName() == "table-cell" ) {
01089             ++cellNum;
01090             if ( cellNum > numberHeaderColumns ) {
01091                 QDomElement pElem = KoDom::namedItemNS( elem, KoXmlNS::text, "p" );
01092                 m_colLabels.append( pElem.text() );
01093             }
01094         }
01095     }
01096     numberDataColumns = QMAX( numberDataColumns, cellNum - numberHeaderColumns );
01097     if ( (int)m_colLabels.count() != numberDataColumns )
01098         kdWarning(35001) << "Got " << m_colLabels.count()
01099              << " column titles, expected " << numberDataColumns
01100              << endl;
01101 
01102     // Get the number of rows, and read row labels
01103     int          numberDataRows = 0;
01104     QDomElement  tableRows = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-rows" );
01105 
01106     m_rowLabels.clear();
01107     forEachElement( elem, tableRows ) {
01108         if ( elem.localName() == "table-row" ) {
01109             int repeated = elem.attributeNS( KoXmlNS::table, "number-rows-repeated", QString::null ).toInt();
01110             Q_ASSERT( repeated <= 1 ); // we don't handle yet the case where data rows are repeated (can this really happen?)
01111             numberDataRows += QMAX( 1, repeated );
01112             if ( numberHeaderColumns > 0 ) {
01113                 QDomElement firstCell = KoDom::namedItemNS( elem, KoXmlNS::table, "table-cell" );
01114                 QDomElement pElem = KoDom::namedItemNS( firstCell, KoXmlNS::text, "p" );
01115                 m_rowLabels.append( pElem.text() );
01116             }
01117         }
01118     }
01119 
01120     kdDebug(35001) << "numberHeaderColumns=" << numberHeaderColumns
01121            << " numberDataColumns=" << numberDataColumns
01122                    << " numberDataRows=" << numberDataRows << endl;
01123 
01124     if ( (int)m_rowLabels.count() != numberDataRows)
01125         kdWarning(35001) << "Got " << m_rowLabels.count()
01126              << " row labels, expected " << numberDataRows << endl;
01127 
01128     m_currentData.expand( numberDataRows, numberDataColumns );
01129     m_currentData.setUsedCols( numberDataColumns );
01130     m_currentData.setUsedRows( numberDataRows );
01131 
01132     // Now really load the cells.
01133     int row = 0;
01134     QDomElement rowElem;
01135     forEachElement( rowElem, tableRows ) {
01136         if ( rowElem.localName() == "table-row" ) {
01137             int col = 0;
01138             int cellNum = 0;
01139             QDomElement cellElem;
01140             forEachElement( cellElem, rowElem ) {
01141                 if ( cellElem.localName() == "table-cell" ) {
01142                     ++cellNum;
01143                     if ( cellNum > numberHeaderColumns ) {
01144                         QString valueType = cellElem.attributeNS( KoXmlNS::office, "value-type", QString::null );
01145                         if ( valueType != "float" )
01146                             kdWarning(35001) << "Don't know how to handle value-type " << valueType << endl;
01147                         else {
01148                             QString  value = cellElem.attributeNS( KoXmlNS::office, "value", QString::null );
01149                             double   val = value.toDouble();
01150 
01151                             m_currentData.setCell( row, col, val );
01152                         }
01153                         ++col;
01154                     }
01155                 }
01156             }
01157             ++row;
01158         }
01159     }
01160 
01161     return true;
01162 }
01163 
01164 
01165 bool KChartPart::saveOasis( KoStore* store, KoXmlWriter* manifestWriter )
01166 {
01167     manifestWriter->addManifestEntry( "content.xml", "text/xml" );
01168     KoOasisStore oasisStore( store );
01169 
01170     KoXmlWriter* contentWriter = oasisStore.contentWriter();
01171     if ( !contentWriter )
01172         return false;
01173 
01174     KoGenStyles mainStyles;
01175 
01176     KoXmlWriter* bodyWriter = oasisStore.bodyWriter();
01177     bodyWriter->startElement( "office:body" );
01178     bodyWriter->startElement( "office:chart" );
01179     bodyWriter->startElement( "chart:chart" );
01180 
01181     // Indent to indicate that this is inside some tags.
01182     {
01183         // Saves chart class, title, legend, plot-area
01184         m_params->saveOasis( bodyWriter, mainStyles );
01185 
01186     // Save the data table.
01187         saveOasisData( bodyWriter, mainStyles );
01188     }
01189 
01190     bodyWriter->endElement(); // chart:chart
01191     bodyWriter->endElement(); // office:chart
01192     bodyWriter->endElement(); // office:body
01193 
01194     contentWriter->startElement( "office:automatic-styles" );
01195     writeAutomaticStyles( *contentWriter, mainStyles );
01196     contentWriter->endElement(); // office:automatic-styles
01197 
01198     oasisStore.closeContentWriter();
01199 
01200     // Done with content.xml
01201 
01202 #if 0
01203     if ( !store->open( "styles.xml" ) )
01204         return false;
01205     manifestWriter->addManifestEntry( "styles.xml", "text/xml" );
01206     saveOasisDocumentStyles( store, mainStyles, savingContext, saveFlag,
01207                  headerFooterContent );
01208     if ( !store->close() ) // done with styles.xml
01209         return false;
01210 #endif
01211 
01212     return true;
01213 }
01214 
01215 
01216 void KChartPart::saveOasisData( KoXmlWriter* bodyWriter,
01217                 KoGenStyles& mainStyles ) const
01218 {
01219     Q_UNUSED( mainStyles );
01220 
01221     const int cols = m_currentData.usedCols()
01222                      ? QMIN(m_currentData.usedCols(), m_currentData.cols())
01223                      : m_currentData.cols();
01224     const int rows = m_currentData.usedRows()
01225                      ? QMIN(m_currentData.usedRows(), m_currentData.rows())
01226                      : m_currentData.rows();
01227 
01228     bodyWriter->startElement( "table:table" );
01229     bodyWriter->addAttribute( "table:name", "local-table" );
01230 
01231     // Exactly one header column, always.
01232     bodyWriter->startElement( "table:table-header-columns" );
01233     bodyWriter->startElement( "table:table-column" );
01234     bodyWriter->endElement(); // table:table-column
01235     bodyWriter->endElement(); // table:table-header-columns
01236 
01237     // Then "cols" columns
01238     bodyWriter->startElement( "table:table-columns" );
01239     bodyWriter->startElement( "table:table-column" );
01240     bodyWriter->addAttribute( "table:number-columns-repeated", cols );
01241     bodyWriter->endElement(); // table:table-column
01242     bodyWriter->endElement(); // table:table-columns
01243 
01244     // Exactly one header row, always.
01245     bodyWriter->startElement( "table:table-header-rows" );
01246     bodyWriter->startElement( "table:table-row" );
01247 
01248     // The first column in header row is just the header column - no title needed
01249     bodyWriter->startElement( "table:table-cell" );
01250     bodyWriter->addAttribute( "office:value-type", "string" );
01251     bodyWriter->startElement( "text:p" );
01252     bodyWriter->endElement(); // text:p
01253     bodyWriter->endElement(); // table:table-cell
01254 
01255     // Save column labels in the first header row, for instance:
01256     //          <table:table-cell office:value-type="string">
01257     //            <text:p>Column 1 </text:p>
01258     //          </table:table-cell>
01259     QStringList::const_iterator colLabelIt = m_colLabels.begin();
01260     for ( int col = 0; col < cols ; ++col ) {
01261         if ( colLabelIt != m_colLabels.end() ) {
01262             bodyWriter->startElement( "table:table-cell" );
01263             bodyWriter->addAttribute( "office:value-type", "string" );
01264             bodyWriter->startElement( "text:p" );
01265             bodyWriter->addTextNode( *colLabelIt );
01266             bodyWriter->endElement(); // text:p
01267             bodyWriter->endElement(); // table:table-cell
01268             ++colLabelIt;
01269         }
01270     }
01271 
01272     bodyWriter->endElement(); // table:table-row
01273     bodyWriter->endElement(); // table:table-header-rows
01274     bodyWriter->startElement( "table:table-rows" );
01275 
01276     QStringList::const_iterator rowLabelIt = m_rowLabels.begin();
01277     for ( int row = 0; row < rows ; ++row ) {
01278         bodyWriter->startElement( "table:table-row" );
01279 
01280         if ( rowLabelIt != m_rowLabels.end() ) {
01281             // Save row labels, similar to column labels
01282             bodyWriter->startElement( "table:table-cell" );
01283             bodyWriter->addAttribute( "office:value-type", "string" );
01284 
01285             bodyWriter->startElement( "text:p" );
01286             bodyWriter->addTextNode( *rowLabelIt );
01287             bodyWriter->endElement(); // text:p
01288 
01289             bodyWriter->endElement(); // table:table-cell
01290             ++rowLabelIt;
01291         }
01292 
01293         for ( int col = 0; col < cols; ++col ) {
01294             QVariant value( m_currentData.cellVal( row, col ) );
01295             QString  valType;
01296             QString  valStr;
01297 
01298             switch ( value.type() ) {
01299             case QVariant::Invalid:
01300         break;
01301             case QVariant::String:
01302         valType = "string";
01303         valStr  = value.toString();
01304         break;
01305             case QVariant::Double:
01306         valType = "float";
01307         valStr  = QString::number( value.toDouble(), 'g', DBL_DIG );
01308         break;
01309             case QVariant::DateTime:
01310         valType = "date";
01311         valStr  = ""; /* like in saveXML, but why? */
01312         break;
01313             default: {
01314                 kdDebug(35001) << "ERROR: cell " << row << "," << col
01315                                << " has unknown type." << endl;
01316                 }
01317             }
01318 
01319         // Add the value type and the string to the XML tree.
01320             bodyWriter->startElement( "table:table-cell" );
01321             if ( !valType.isEmpty() ) {
01322                 bodyWriter->addAttribute( "office:value-type", valType );
01323                 if ( value.type() == QVariant::Double )
01324                     bodyWriter->addAttribute( "office:value", valStr );
01325 
01326                 bodyWriter->startElement( "text:p" );
01327                 bodyWriter->addTextNode( valStr );
01328                 bodyWriter->endElement(); // text:p
01329             }
01330         bodyWriter->endElement(); // table:table-cell
01331         }
01332         bodyWriter->endElement(); // table:table-row
01333     }
01334 
01335     bodyWriter->endElement(); // table:table-rows
01336     bodyWriter->endElement(); // table:table
01337 }
01338 
01339 void KChartPart::writeAutomaticStyles( KoXmlWriter& contentWriter, KoGenStyles& mainStyles ) const
01340 {
01341     QValueList<KoGenStyles::NamedStyle> styles = mainStyles.styles( KoGenStyle::STYLE_AUTO );
01342     QValueList<KoGenStyles::NamedStyle>::const_iterator it = styles.begin();
01343     for ( ; it != styles.end() ; ++it ) {
01344         (*it).style->writeStyle( &contentWriter, mainStyles, "style:style", (*it).name, "style:chart-properties" );
01345     }
01346 
01347 }
01348 
01349 // ----------------------------------------------------------------
01350 //             Save and Load old KChart file format
01351 
01352 
01353 QDomDocument KChartPart::saveXML()
01354 {
01355     QDomElement  tmpElem;
01356 
01357     //kdDebug(35001) << "kchart saveXML called" << endl;
01358 
01359     // The biggest part of the saving is done by KDChart itself, so we
01360     // don't have to do it.
01361     QDomDocument doc = m_params->saveXML( false );
01362 
01363     // ----------------------------------------------------------------
01364     // The rest of the saving has to be done by us.
01365 
01366     QDomElement docRoot = doc.documentElement();
01367 
01368     // Save auxiliary data.
01369     QDomElement aux = doc.createElement( "KChartAuxiliary" );
01370     docRoot.appendChild( aux );
01371 
01372     // The data direction (rows/columns).
01373     tmpElem = doc.createElement( "direction" );
01374     tmpElem.setAttribute( "value", (int) m_params->dataDirection() );
01375     aux.appendChild( tmpElem );
01376 
01377     tmpElem = doc.createElement( "dataaslabel" );
01378     tmpElem.setAttribute( "firstrow",
01379               m_params->firstRowAsLabel() ? "true" : "false" );
01380     tmpElem.setAttribute( "firstcol",
01381               m_params->firstColAsLabel() ? "true" : "false" );
01382     aux.appendChild( tmpElem );
01383 
01384     tmpElem = doc.createElement( "barnumlines" );
01385     tmpElem.setAttribute( "value", (int) m_params->barNumLines() );
01386     aux.appendChild( tmpElem );
01387 
01388     // Save the data values.
01389     QDomElement data = doc.createElement( "data" );
01390     docRoot.appendChild( data );
01391 
01392     int cols = m_currentData.usedCols()
01393              ? QMIN(m_currentData.usedCols(), m_currentData.cols())
01394              : m_currentData.cols();
01395     int rows = m_currentData.usedRows()
01396              ? QMIN(m_currentData.usedRows(), m_currentData.rows())
01397              : m_currentData.rows();
01398     data.setAttribute( "cols", cols );
01399     data.setAttribute( "rows", rows );
01400     kdDebug(35001) << "      writing  " << cols << "," << rows << "  (cols,rows)." << endl;
01401 
01402     for (int i=0; i!=rows; ++i) {
01403         for (int j=0; j!=cols; ++j) {
01404             QDomElement e = doc.createElement( "cell" );
01405             data.appendChild( e );
01406             QString valType;
01407             QVariant value( m_currentData.cellVal( i,j ) );
01408             switch ( value.type() ) {
01409                 case QVariant::Invalid:  valType = "NoValue";   break;
01410                 case QVariant::String:   valType = "String";    break;
01411                 case QVariant::Double:   valType = "Double";    break;
01412                 case QVariant::DateTime: valType = "DateTime";  break;
01413                 default: {
01414                     valType = "(unknown)";
01415                     kdDebug(35001) << "ERROR: cell " << i << "," << j
01416                    << " has unknown type." << endl;
01417                 }
01418             }
01419 
01420             e.setAttribute( "valType", valType );
01421             //kdDebug(35001) << "      cell " << i << "," << j
01422         //     << " saved with type '" << valType << "'." << endl;
01423             switch ( value.type() ) {
01424                 case QVariant::String:  e.setAttribute( "value", value.toString() );
01425                               break;
01426                 case QVariant::Double:  e.setAttribute( "value", QString::number( value.toDouble() ) );
01427                               break;
01428                 case QVariant::DateTime:e.setAttribute( "value", "" );
01429                               break;
01430                 default: {
01431                     e.setAttribute( "value", "" );
01432                     if( QVariant::Invalid != value.type() )
01433                         kdDebug(35001) << "ERROR: cell " << i << "," << j
01434                        << " has unknown type." << endl;
01435                 }
01436             }
01437         }
01438     }
01439 
01440     return doc;
01441 }
01442 
01443 
01444 bool KChartPart::loadXML( QIODevice*, const QDomDocument& doc )
01445 {
01446     kdDebug(35001) << "kchart loadXML called" << endl;
01447 
01448     // Set some sensible defaults.
01449     setChartDefaults();
01450 
01451     // First try to load the KDChart parameters.
01452     bool  result = m_params->loadXML( doc );
01453 
01454     // If went well, try to load the auxiliary data and the data...
01455     if (result) {
01456         result = loadAuxiliary(doc) && loadData( doc, m_currentData );
01457     }
01458     else {
01459     // ...but if it did, try to load the old XML format.
01460         result = loadOldXML( doc );
01461     }
01462 
01463     // If everything is OK, then get the headers from the KDChart parameters.
01464     if (result) {
01465         QStringList        legendLabels;
01466         KDChartAxisParams  params;
01467         params = m_params->axisParams( KDChartAxisParams::AxisPosBottom );
01468 
01469     // Get the legend.
01470     QString  str;
01471     uint     index = 0;
01472     while ((str = m_params->legendText(index++)) != QString::null)
01473         legendLabels << str;
01474 
01475     if (m_params->dataDirection() == KChartParams::DataRows) {
01476         m_colLabels = params.axisLabelStringList();
01477         m_rowLabels = legendLabels;
01478     }
01479     else {
01480         m_colLabels = legendLabels;
01481         m_rowLabels = params.axisLabelStringList();
01482     }
01483 
01484     }
01485 
01486     m_params->setDrawSolidExcessArrows(true);
01487 
01488     return result;
01489 }
01490 
01491 
01492 // Load the auxiliary data.
01493 //
01494 // Currently, that means the data direction.
01495 //
01496 bool KChartPart::loadAuxiliary( const QDomDocument& doc )
01497 {
01498     QDomElement  chart = doc.documentElement();
01499     QDomElement  aux   = chart.namedItem("KChartAuxiliary").toElement();
01500 
01501     // Older XML files might be missing this section.  That is OK; the
01502     // defaults will be used.
01503     if (aux.isNull())
01504     return true;
01505 
01506     QDomNode node = aux.firstChild();
01507 
01508     // If the aux section exists, it should contain data.
01509     while (!node.isNull()) {
01510 
01511     QDomElement e = node.toElement();
01512     if (e.isNull()) {
01513         // FIXME: Should this be regarded as an error?
01514         node = node.nextSibling();
01515         continue;
01516     }
01517 
01518     // Check for direction
01519     if ( e.tagName() == "direction" ) {
01520         if ( e.hasAttribute("value") ) {
01521         bool  ok;
01522 
01523         // Read the direction. On failure, use the default.
01524         int   dir = e.attribute("value").toInt(&ok);
01525         if ( !ok )
01526             dir = (int) KChartParams::DataColumns;
01527 
01528         //kdDebug(35001) << "Got aux value \"direction\": " << dir << endl;
01529         m_params->setDataDirection( (KChartParams::DataDirection) dir );
01530         }
01531         else {
01532         kdDebug(35001) << "Error in direction tag." << endl;
01533         }
01534     }
01535 
01536     // Check for first row / col as label
01537     else if ( e.tagName() == "dataaslabel" ) {
01538         QString  val;
01539 
01540         if ( e.hasAttribute("firstrow") ) {
01541         // Read the direction. On failure, use the default.
01542         val = e.attribute("firstrow");
01543         if ( val == "true" )
01544             m_params->setFirstRowAsLabel( true );
01545         else
01546             m_params->setFirstRowAsLabel( false );
01547         }
01548         else {
01549         kdDebug(35001) << "Error in barnumlines tag." << endl;
01550         m_params->setFirstRowAsLabel( false );
01551         }
01552 
01553         if ( e.hasAttribute("firstcol") ) {
01554         // Read the direction. On failure, use the default.
01555         val = e.attribute("firstcol");
01556         if ( val == "true" )
01557             m_params->setFirstColAsLabel( true );
01558         else
01559             m_params->setFirstColAsLabel( false );
01560         }
01561         else {
01562         kdDebug(35001) << "Error in barnumlines tag." << endl;
01563         m_params->setFirstColAsLabel( false );
01564         }
01565     }
01566 
01567     // Check for number of lines in a bar chart.
01568     else if ( e.tagName() == "barnumlines" ) {
01569         if ( e.hasAttribute("value") ) {
01570         bool  ok;
01571 
01572         // Read the number of lines. On failure, use the default.
01573         int   barNumLines = e.attribute("value").toInt(&ok);
01574         if ( !ok )
01575             barNumLines = 0;
01576 
01577         //kdDebug(35001) << "Got aux value \"barnumlines\": "
01578         //         << barNumLines << endl;
01579         m_params->setBarNumLines( barNumLines );
01580         }
01581         else {
01582         kdDebug(35001) << "Error in barnumlines tag." << endl;
01583         }
01584     }
01585 #if 0
01586     // Expand with more auxiliary types when needed.
01587     else if ( e.tagName() == "..." ) {
01588     }
01589     and so on...
01590 #endif
01591 
01592     node = node.nextSibling();
01593     }
01594 
01595     return true;
01596 }
01597 
01598 
01599 bool KChartPart::loadData( const QDomDocument& doc,
01600                KDChartTableData& m_currentData )
01601 {
01602     kdDebug(35001) << "kchart loadData called" << endl;
01603 
01604     QDomElement chart = doc.documentElement();
01605     QDomElement data = chart.namedItem("data").toElement();
01606     bool ok;
01607     int cols = data.attribute("cols").toInt(&ok);
01608     kdDebug(35001) << "cols readed as:" << cols << endl;
01609     if ( !ok ){
01610          return false;
01611     }
01612 
01613     int rows = data.attribute("rows").toInt(&ok);
01614     if ( !ok ){
01615          return false;
01616     }
01617 
01618     kdDebug(35001) << rows << " x " << cols << endl;
01619     m_currentData.expand(rows, cols);
01620     m_currentData.setUsedCols( cols );
01621     m_currentData.setUsedRows( rows );
01622     kdDebug(35001) << "Expanded!" << endl;
01623     QDomNode n = data.firstChild();
01624     //QArray<int> tmpExp(rows*cols);
01625     //QArray<bool> tmpMissing(rows*cols);
01626     for (int i=0; i!=rows; i++) {
01627         for (int j=0; j!=cols; j++) {
01628             if (n.isNull()) {
01629                 kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
01630                 break;
01631             }
01632             QDomElement e = n.toElement();
01633             if ( !e.isNull() && e.tagName() == "cell" ) {
01634                 // add the cell to the corresponding place...
01635                 QVariant t;
01636                 if ( e.hasAttribute("value") && e.hasAttribute("valType") ) {
01637                     QString valueType = e.attribute("valType").lower();
01638                     if ( "string" == valueType ) {
01639                         t = e.attribute("value");
01640                     }
01641                     else if ( "double" == valueType ) {
01642                         bool bOk;
01643                         double val = e.attribute("value").toDouble(&bOk);
01644                         if ( !bOk )
01645                             val = 0.0;
01646                         t = val;
01647                     /*
01648                     } else if ( "datetime" == valueType ) {
01649                         t = . . .
01650                     */
01651                     } else {
01652                         t.clear();
01653                         if ( "novalue" != valueType )
01654                             kdDebug(35001) << "ERROR: cell " << i << "," << j << " has unknown type '" << valueType << "'." << endl;
01655                     }
01656                 } else
01657                     t.clear();
01658 
01659                 m_currentData.setCell(i,j, t );
01660 
01661         /*
01662                 if ( e.hasAttribute( "hide" ) ) {
01663                     tmpMissing[cols*j+i] = (bool)e.attribute("hide").toInt( &ok );
01664                     if ( !ok )
01665                         return false;
01666                 } else {
01667                     tmpMissing[cols*j+i] = false;
01668                 }
01669                 if ( e.hasAttribute( "dist" ) ) {
01670                     tmpExp[cols*j+i] = e.attribute("dist").toInt( &ok );
01671                     if ( !ok )
01672                         return false;
01673                 } else {
01674                     tmpExp[cols*j+i] = 0;
01675                 }
01676         */
01677 
01678                 n = n.nextSibling();
01679             }
01680         }
01681     }
01682     /*
01683     m_params->missing=tmpMissing;
01684     m_params->explode=tmpExp;
01685     */
01686     return true;
01687 }
01688 
01689 
01690 // ----------------------------------------------------------------
01691 //         Save and Load real old KChart file format
01692 
01693 
01694 bool KChartPart::loadOldXML( const QDomDocument& doc )
01695 {
01696     kdDebug(35001) << "kchart loadOldXML called" << endl;
01697     if ( doc.doctype().name() != "chart" )
01698         return false;
01699 
01700     kdDebug(35001) << "Ok, it is a chart" << endl;
01701 
01702     QDomElement chart = doc.documentElement();
01703     if ( chart.attribute( "mime" ) != "application/x-kchart" && chart.attribute( "mime" ) != "application/vnd.kde.kchart" )
01704         return false;
01705 
01706     kdDebug(35001) << "Mimetype ok" << endl;
01707 
01708 #if 0
01709     QDomElement data = chart.namedItem("data").toElement();
01710     bool ok;
01711     int cols = data.attribute("cols").toInt(&ok);
01712     kdDebug(35001) << "cols readed as:" << cols << endl;
01713     if (!ok)  { return false; }
01714     int rows = data.attribute("rows").toInt(&ok);
01715     if (!ok)  { return false; }
01716     kdDebug(35001) << rows << " x " << cols << endl;
01717     m_currentData.expand(rows, cols);
01718     kdDebug(35001) << "Expanded!" << endl;
01719     QDomNode n = data.firstChild();
01720     QArray<int> tmpExp(rows*cols);
01721     QArray<bool> tmpMissing(rows*cols);
01722 
01723     for (int i=0; i!=rows; i++) {
01724         for (int j=0; j!=cols; j++) {
01725             if (n.isNull()) {
01726                 kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
01727                 break;
01728             }
01729 
01730             QDomElement e = n.toElement();
01731             if ( !e.isNull() && e.tagName() == "cell" ) {
01732                 // add the cell to the corresponding place...
01733                 double val = e.attribute("value").toDouble(&ok);
01734                 if (!ok)  {  return false; }
01735                 kdDebug(35001) << i << " " << j << "=" << val << endl;
01736                 KoChart::Value t( val );
01737                 // kdDebug(35001) << "Set cell for " << row << "," << col << endl;
01738                 m_currentData.setCell(i,j,t);
01739                 if ( e.hasAttribute( "hide" ) ) {
01740                     tmpMissing[cols*j+i] = (bool)e.attribute("hide").toInt( &ok );
01741                     if ( !ok )
01742                         return false;
01743                 } else {
01744                     tmpMissing[cols*j+i] = false;
01745                 }
01746                 if ( e.hasAttribute( "dist" ) ) {
01747                     tmpExp[cols*j+i] = e.attribute("dist").toInt( &ok );
01748                     if ( !ok )
01749                         return false;
01750                 } else {
01751                     tmpExp[cols*j+i] = 0;
01752                 }
01753 
01754                 n = n.nextSibling();
01755             }
01756         }
01757     }
01758     m_params->missing=tmpMissing;
01759     m_params->explode=tmpExp;
01760 #endif
01761 
01762 
01763 /*
01764   enum KChartType {
01765   KCHARTTYPE_LINE,
01766   KCHARTTYPE_AREA,
01767   KCHARTTYPE_BAR,
01768   KCHARTTYPE_HILOCLOSE,
01769   KCHARTTYPE_COMBO_LINE_BAR, aka, VOL[ume]
01770   KCHARTTYPE_COMBO_HLC_BAR,
01771   KCHARTTYPE_COMBO_LINE_AREA,
01772   KCHARTTYPE_COMBO_HLC_AREA,
01773   KCHARTTYPE_3DHILOCLOSE,
01774   KCHARTTYPE_3DCOMBO_LINE_BAR,
01775   KCHARTTYPE_3DCOMBO_LINE_AREA,
01776   KCHARTTYPE_3DCOMBO_HLC_BAR,
01777   KCHARTTYPE_3DCOMBO_HLC_AREA,
01778   KCHARTTYPE_3DBAR,
01779   KCHARTTYPE_3DAREA,
01780   KCHARTTYPE_3DLINE,
01781   KCHARTTYPE_3DPIE,
01782   KCHARTTYPE_2DPIE
01783   };
01784 */
01785     bool ok;
01786     QDomElement params = chart.namedItem( "params" ).toElement();
01787     if ( params.hasAttribute( "type" ) ) {
01788         int type=params.attribute("type").toInt( &ok );
01789         if ( !ok )
01790             return false;
01791         switch(type)
01792         {
01793         case 1:
01794             m_params->setChartType(KChartParams::Line);
01795             break;
01796         case 2:
01797             m_params->setChartType(KChartParams::Area);
01798             break;
01799         case 3:
01800             m_params->setChartType(KChartParams::Bar);
01801             break;
01802         case 4:
01803             m_params->setChartType(KChartParams::HiLo);
01804             break;
01805         case 5:
01806         case 6:
01807         case 7:
01808         case 8:
01809             /*     KCHARTTYPE_COMBO_LINE_BAR, aka, VOL[ume]
01810                    KCHARTTYPE_COMBO_HLC_BAR,
01811                    KCHARTTYPE_COMBO_LINE_AREA,
01812                    KCHARTTYPE_COMBO_HLC_AREA,
01813             */
01814             /* line by default*/
01815             m_params->setChartType(KChartParams::Line);
01816             break;
01817         case 9:
01818             m_params->setChartType(KChartParams::HiLo);
01819             break;
01820         case 10:
01821             m_params->setChartType(KChartParams::Bar);
01822             break;
01823         case 11:
01824             m_params->setChartType(KChartParams::Area);
01825             break;
01826         case 12:
01827             m_params->setChartType(KChartParams::Bar);
01828             break;
01829         case 13:
01830             m_params->setChartType(KChartParams::Area);
01831             break;
01832         case 14:
01833             m_params->setChartType(KChartParams::Bar);
01834             break;
01835         case 15:
01836             m_params->setChartType(KChartParams::Area);
01837             break;
01838         case 16:
01839             m_params->setChartType(KChartParams::Line);
01840             break;
01841         case 17:
01842         case 18:
01843             m_params->setChartType(KChartParams::Pie);
01844             break;
01845 
01846         }
01847         if ( !ok )
01848             return false;
01849     }
01850 #if 0
01851     if ( params.hasAttribute( "subtype" ) ) {
01852         m_params->stack_type = (KChartStackType)params.attribute("subtype").toInt( &ok );
01853         if ( !ok )
01854             return false;
01855     }
01856     if ( params.hasAttribute( "hlc_style" ) ) {
01857         m_params->hlc_style = (KChartHLCStyle)params.attribute("hlc_style").toInt( &ok );
01858         if ( !ok )
01859             return false;
01860     }
01861     if ( params.hasAttribute( "hlc_cap_width" ) ) {
01862         m_params->hlc_cap_width = (short)params.attribute( "hlc_cap_width" ).toShort( &ok );
01863         if ( !ok )
01864             return false;
01865     }
01866 
01867     QDomElement title = params.namedItem( "title" ).toElement();
01868     if ( !title.isNull()) {
01869         QString t = title.text();
01870         m_params->title=t;
01871     }
01872     QDomElement titlefont = params.namedItem( "titlefont" ).toElement();
01873     if ( !titlefont.isNull()) {
01874         QDomElement font = titlefont.namedItem( "font" ).toElement();
01875         if ( !font.isNull() )
01876             m_params->setTitleFont(toFont(font));
01877     }
01878     QDomElement xtitle = params.namedItem( "xtitle" ).toElement();
01879     if ( !xtitle.isNull()) {
01880         QString t = xtitle.text();
01881         m_params->xtitle=t;
01882     }
01883     QDomElement xtitlefont = params.namedItem( "xtitlefont" ).toElement();
01884     if ( !xtitlefont.isNull()) {
01885         QDomElement font = xtitlefont.namedItem( "font" ).toElement();
01886         if ( !font.isNull() )
01887             m_params->setXTitleFont(toFont(font));
01888     }
01889     QDomElement ytitle = params.namedItem( "ytitle" ).toElement();
01890     if ( !ytitle.isNull()) {
01891         QString t = ytitle.text();
01892         m_params->ytitle=t;
01893     }
01894     QDomElement ytitle2 = params.namedItem( "ytitle2" ).toElement();
01895     if ( !ytitle2.isNull()) {
01896         QString t = ytitle2.text();
01897         m_params->ytitle2=t;
01898     }
01899     QDomElement ytitlefont = params.namedItem( "ytitlefont" ).toElement();
01900     if ( !ytitlefont.isNull()) {
01901         QDomElement font = ytitlefont.namedItem( "font" ).toElement();
01902         if ( !font.isNull() )
01903             m_params->setYTitleFont(toFont(font));
01904     }
01905     QDomElement ylabelfmt = params.namedItem( "ylabelfmt" ).toElement();
01906     if ( !ylabelfmt.isNull()) {
01907         QString t = ylabelfmt.text();
01908         m_params->ylabel_fmt=t;
01909     }
01910     QDomElement ylabel2fmt = params.namedItem( "ylabel2fmt" ).toElement();
01911     if ( !ylabel2fmt.isNull()) {
01912         QString t = ylabel2fmt.text();
01913         m_params->ylabel2_fmt=t;
01914     }
01915     QDomElement labelfont = params.namedItem( "labelfont" ).toElement();
01916     if ( !labelfont.isNull()) {
01917         QDomElement font = labelfont.namedItem( "font" ).toElement();
01918         if ( !font.isNull() )
01919             m_params->setLabelFont(toFont(font));
01920     }
01921 
01922     QDomElement yaxisfont = params.namedItem( "yaxisfont" ).toElement();
01923     if ( !yaxisfont.isNull()) {
01924         QDomElement font = yaxisfont.namedItem( "font" ).toElement();
01925         if ( !font.isNull() )
01926             m_params->setYAxisFont(toFont(font));
01927     }
01928 
01929     QDomElement xaxisfont = params.namedItem( "xaxisfont" ).toElement();
01930     if ( !xaxisfont.isNull()) {
01931         QDomElement font = xaxisfont.namedItem( "font" ).toElement();
01932         if ( !font.isNull() )
01933             m_params->setXAxisFont(toFont(font));
01934     }
01935     QDomElement annotationFont = params.namedItem("annotationfont").toElement();
01936     if ( !annotationFont.isNull()) {
01937         QDomElement font = annotationFont.namedItem( "font" ).toElement();
01938         if ( !font.isNull() )
01939             m_params->setAnnotationFont(toFont(font));
01940     }
01941 
01942     QDomElement yaxis = params.namedItem( "yaxis" ).toElement();
01943     if ( !yaxis.isNull()) {
01944         if (yaxis.hasAttribute( "yinterval" )) {
01945             m_params->requested_yinterval= yaxis.attribute("yinterval").toDouble( &ok );
01946             if ( !ok ) return false;
01947         }
01948         if (yaxis.hasAttribute( "ymin" )) {
01949             m_params->requested_ymin= yaxis.attribute("ymin").toDouble( &ok );
01950             if ( !ok ) return false;
01951         }
01952         if (yaxis.hasAttribute( "ymax" ) ) {
01953             m_params->requested_ymax= yaxis.attribute("ymax").toDouble( &ok );
01954             if ( !ok ) return false;
01955         }
01956     }
01957 #endif
01958 
01959     QDomElement graph = params.namedItem( "graph" ).toElement();
01960     if (!graph.isNull()) {
01961         if (graph.hasAttribute( "grid" )) {
01962             bool b=(bool) graph.attribute("grid").toInt( &ok );
01963             m_params->setAxisShowGrid(KDChartAxisParams::AxisPosLeft,b );
01964             m_params->setAxisShowGrid(KDChartAxisParams::AxisPosBottom,b );
01965             if (!ok) return false;
01966         }
01967         if (graph.hasAttribute( "xaxis" )) {
01968             bool b=(bool) graph.attribute("xaxis").toInt( &ok );
01969             if (!ok) return false;
01970             m_params->setAxisVisible(KDChartAxisParams::AxisPosBottom,b);
01971         }
01972         if (graph.hasAttribute( "yaxis" )) {
01973             bool b=(bool) graph.attribute("yaxis").toInt( &ok );
01974             if (!ok) return false;
01975             m_params->setAxisVisible(KDChartAxisParams::AxisPosLeft,b);
01976         }
01977 #if 0
01978         //no implemented
01979         if (graph.hasAttribute( "shelf" )) {
01980             m_params->shelf=(bool) graph.attribute("shelf").toInt( &ok );
01981             if (!ok) return false;
01982         }
01983 #endif
01984         if (graph.hasAttribute( "yaxis2" )) {
01985             bool b=(bool) graph.attribute("yaxis2").toInt( &ok );
01986             if (!ok) return false;
01987             m_params->setAxisVisible(KDChartAxisParams::AxisPosRight,b);
01988         }
01989 
01990 #if 0
01991         //no implemented
01992         if (graph.hasAttribute( "ystyle" )) {
01993             m_params->yval_style=(bool) graph.attribute("ystyle").toInt( &ok );
01994             if (!ok) return false;
01995         }
01996         if (graph.hasAttribute( "border" )) {
01997             m_params->border=(bool) graph.attribute("border").toInt( &ok );
01998             if (!ok) return false;
01999         }
02000         if (graph.hasAttribute( "transbg" )) {
02001             m_params->transparent_bg=(bool) graph.attribute("transbg").toInt( &ok );
02002             if (!ok) return false;
02003         }
02004         if (graph.hasAttribute( "xlabel" )) {
02005             m_params->hasxlabel=(bool) graph.attribute("xlabel").toInt( &ok );
02006             if (!ok) return false;
02007         }
02008         if ( graph.hasAttribute( "xlabel_spacing" ) ) {
02009             m_params->xlabel_spacing = (short)graph.attribute( "xlabel_spacing" ).toShort( &ok );
02010             if ( !ok )
02011                 return false;
02012         }
02013         if ( graph.hasAttribute( "ylabel_density" ) ) {
02014             m_params->ylabel_density = (short)graph.attribute( "ylabel_density" ).toShort( &ok );
02015             if ( !ok )
02016                 return false;
02017         }
02018         if (graph.hasAttribute( "line")) {
02019             m_params->label_line=(bool) graph.attribute("line").toInt( &ok );
02020             if (!ok) return false;
02021         }
02022         if (graph.hasAttribute( "percent")) {
02023             m_params->percent_labels=(KChartPercentType) graph.attribute("percent").toInt( &ok );
02024             if (!ok) return false;
02025         }
02026         if (graph.hasAttribute("cross")) {
02027             m_params->cross=(bool) graph.attribute("cross").toInt( &ok );
02028             if (!ok) return false;
02029         }
02030         if (graph.hasAttribute("thumbnail")) {
02031             m_params->thumbnail=(bool) graph.attribute("thumbnail").toInt( &ok );
02032             if (!ok) return false;
02033         }
02034         if (graph.hasAttribute("thumblabel")) {
02035             m_params->thumblabel= graph.attribute("thumblabel");
02036         }
02037         if (graph.hasAttribute("thumbval")) {
02038             m_params->thumbval=(bool) graph.attribute("thumbval").toDouble( &ok );
02039             if (!ok)
02040                 return false;
02041         }
02042 #endif
02043     }
02044 
02045 #if 0
02046     QDomElement graphparams = params.namedItem( "graphparams" ).toElement();
02047     if (!graphparams.isNull()) {
02048         if (graphparams.hasAttribute( "dept3d" )) {
02049             m_params->_3d_depth=graphparams.attribute("dept3d").toDouble( &ok );
02050             if (!ok) return false;
02051         }
02052         if (graphparams.hasAttribute( "angle3d" )) {
02053             m_params->_3d_angle=graphparams.attribute("angle3d").toShort( &ok );
02054             if (!ok) return false;
02055         }
02056         if (graphparams.hasAttribute( "barwidth" )) {
02057             m_params->bar_width=graphparams.attribute("barwidth").toShort( &ok );
02058             if (!ok) return false;
02059         }
02060         if (graphparams.hasAttribute( "colpie" )) {
02061             m_params->colPie=graphparams.attribute("colpie").toInt( &ok );
02062             if (!ok) return false;
02063         }
02064         if (graphparams.hasAttribute( "other_threshold" )) {
02065             m_params->other_threshold=graphparams.attribute("other_threshold").toShort( &ok );
02066             if (!ok)
02067                 return false;
02068         }
02069         if (graphparams.hasAttribute( "offsetCol" )) {
02070             m_params->offsetCol = graphparams.attribute("offsetCol").toInt( &ok );
02071             if (!ok)
02072                 return false;
02073         }
02074         if (graphparams.hasAttribute( "hard_size" )) {
02075             m_params->hard_size = (bool)graphparams.attribute("hard_size").toInt( &ok );
02076             if (!ok)
02077                 return false;
02078         }
02079         if (graphparams.hasAttribute( "hard_graphheight" )) {
02080             m_params->hard_graphheight = graphparams.attribute("hard_graphheight").toInt( &ok );
02081             if (!ok)
02082                 return false;
02083         }
02084         if (graphparams.hasAttribute( "hard_graphwidth" )) {
02085             m_params->hard_graphwidth = graphparams.attribute("hard_graphwidth").toInt( &ok );
02086             if (!ok)
02087                 return false;
02088         }
02089         if (graphparams.hasAttribute( "hard_xorig" )) {
02090             m_params->hard_xorig = graphparams.attribute("hard_xorig").toInt( &ok );
02091             if (!ok)
02092                 return false;
02093         }
02094         if (graphparams.hasAttribute( "hard_yorig" )) {
02095             m_params->hard_yorig = graphparams.attribute("hard_yorig").toInt( &ok );
02096             if (!ok)
02097                 return false;
02098         }
02099         if (graphparams.hasAttribute( "labeldist" )) {
02100             m_params->label_dist=graphparams.attribute("labeldist").toInt( &ok );
02101             if (!ok) return false;
02102         }
02103     }
02104 
02105     QDomElement graphcolor = params.namedItem( "graphcolor" ).toElement();
02106     if (!graphcolor.isNull()) {
02107         if (graphcolor.hasAttribute( "bgcolor" )) {
02108             m_params->BGColor= QColor( graphcolor.attribute( "bgcolor" ) );
02109         }
02110         if (graphcolor.hasAttribute( "gridcolor" )) {
02111             m_params->GridColor= QColor( graphcolor.attribute( "gridcolor" ) );
02112         }
02113         if (graphcolor.hasAttribute( "linecolor" )) {
02114             m_params->LineColor= QColor( graphcolor.attribute( "linecolor" ) );
02115         }
02116         if (graphcolor.hasAttribute( "plotcolor" )) {
02117             m_params->PlotColor= QColor( graphcolor.attribute( "plotcolor" ) );
02118         }
02119         if (graphcolor.hasAttribute( "volcolor" )) {
02120             m_params->VolColor= QColor( graphcolor.attribute( "volcolor" ) );
02121         }
02122         if (graphcolor.hasAttribute( "titlecolor" )) {
02123             m_params->TitleColor= QColor( graphcolor.attribute( "titlecolor" ) );
02124         }
02125         if (graphcolor.hasAttribute( "xtitlecolor" )) {
02126             m_params->XTitleColor= QColor( graphcolor.attribute( "xtitlecolor" ) );
02127         }
02128         if (graphcolor.hasAttribute( "ytitlecolor" )) {
02129             m_params->YTitleColor= QColor( graphcolor.attribute( "ytitlecolor" ) );
02130         }
02131         if (graphcolor.hasAttribute( "ytitle2color" )) {
02132             m_params->YTitle2Color= QColor( graphcolor.attribute( "ytitle2color" ) );
02133         }
02134         if (graphcolor.hasAttribute( "xlabelcolor" )) {
02135             m_params->XLabelColor= QColor( graphcolor.attribute( "xlabelcolor" ) );
02136         }
02137         if (graphcolor.hasAttribute( "ylabelcolor" )) {
02138             m_params->YLabelColor= QColor( graphcolor.attribute( "ylabelcolor" ) );
02139         }
02140         if (graphcolor.hasAttribute( "ylabel2color" )) {
02141             m_params->YLabel2Color= QColor( graphcolor.attribute( "ylabel2color" ) );
02142         }
02143     }
02144 
02145     QDomElement annotation = params.namedItem( "annotation" ).toElement();
02146     if (!annotation.isNull()) {
02147         m_params->annotation=new KChartAnnotationType;
02148         if (annotation.hasAttribute( "color" )) {
02149             m_params->annotation->color= QColor( annotation.attribute( "color" ) );
02150         }
02151         if (annotation.hasAttribute( "point" )) {
02152             m_params->annotation->point=annotation.attribute("point").toDouble( &ok );
02153             if (!ok) return false;
02154         }
02155     }
02156 
02157     QDomElement note = params.namedItem( "note" ).toElement();
02158     if ( !note.isNull()) {
02159         QString t = note.text();
02160         m_params->annotation->note=t;
02161     }
02162 
02163     QDomElement scatter = params.namedItem( "scatter" ).toElement();
02164     if ( !scatter.isNull() ) {
02165         m_params->scatter = new KChartScatterType;
02166         if ( scatter.hasAttribute( "point" ) ) {
02167             m_params->scatter->point = scatter.attribute( "point" ).toDouble( &ok );
02168             if ( !ok )
02169                 return false;
02170         }
02171         if ( scatter.hasAttribute( "val" ) ) {
02172             m_params->scatter->val = scatter.attribute( "val" ).toDouble( &ok );
02173             if ( !ok )
02174                 return false;
02175         }
02176         if ( scatter.hasAttribute( "width" ) ) {
02177             m_params->scatter->width = scatter.attribute( "val" ).toUShort( &ok );
02178             if ( !ok )
02179                 return false;
02180         }
02181         if ( scatter.hasAttribute( "color" )) {
02182             m_params->scatter->color= QColor( scatter.attribute( "color" ) );
02183         }
02184         if ( scatter.hasAttribute( "ind" ) ) {
02185             m_params->scatter->ind = (KChartScatterIndType)scatter.attribute( "ind" ).toInt( &ok );
02186             if ( !ok )
02187                 return false;
02188         }
02189     }
02190 
02191     QDomElement legend = chart.namedItem("legend").toElement();
02192     if (!legend.isNull()) {
02193         int number = legend.attribute("number").toInt(&ok);
02194         if (!ok)  { return false; }
02195         QDomNode name = legend.firstChild();
02196         m_params->legend.clear();
02197         for(int i=0; i<number; i++) {
02198             if (name.isNull()) {
02199                 kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
02200                 break;
02201             }
02202             QDomElement element = name.toElement();
02203             if ( !element.isNull() && element.tagName() == "name" ) {
02204                 QString t = element.text();
02205                 m_params->legend+=t;
02206                 name = name.nextSibling();
02207             }
02208         }
02209     }
02210 
02211     QDomElement xlbl = chart.namedItem("xlbl").toElement();
02212     if (!xlbl.isNull()) {
02213         int number = xlbl.attribute("number").toInt(&ok);
02214         if (!ok)  { return false; }
02215         QDomNode label = xlbl.firstChild();
02216         m_params->xlbl.clear();
02217         for (int i=0; i<number; i++) {
02218             if (label.isNull()) {
02219                 kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
02220                 break;
02221             }
02222             QDomElement element = label.toElement();
02223             if ( !element.isNull() && element.tagName() == "label" ) {
02224                 QString t = element.text();
02225                 m_params->xlbl+=t;
02226                 label = label.nextSibling();
02227             }
02228         }
02229     }
02230 
02231     QDomElement backgroundPixmap = chart.namedItem( "backgroundPixmap" ).toElement();
02232     if ( !backgroundPixmap.isNull() ) {
02233         if ( backgroundPixmap.hasAttribute( "name" ) )
02234             m_params->backgroundPixmapName = backgroundPixmap.attribute( "name" );
02235         if ( backgroundPixmap.hasAttribute( "isDirty" ) ) {
02236             m_params->backgroundPixmapIsDirty = (bool)backgroundPixmap.attribute( "isDirty" ).toInt( &ok );
02237             if ( !ok )
02238                 return false;
02239         }
02240         if ( backgroundPixmap.hasAttribute( "scaled" ) ) {
02241             m_params->backgroundPixmapScaled = (bool)backgroundPixmap.attribute( "scaled" ).toInt( &ok );
02242             if ( !ok )
02243                 return false;
02244         }
02245         if ( backgroundPixmap.hasAttribute( "centered" ) ) {
02246             m_params->backgroundPixmapCentered = (bool)backgroundPixmap.attribute( "centered" ).toInt( &ok );
02247             if ( !ok )
02248                 return false;
02249         }
02250         if ( backgroundPixmap.hasAttribute( "intensity" ) ) {
02251             m_params->backgroundPixmapIntensity = backgroundPixmap.attribute( "intensity" ).toFloat( &ok );
02252             if ( !ok )
02253                 return false;
02254         }
02255     }
02256 
02257     QDomElement extcolor = chart.namedItem("extcolor").toElement();
02258     if (!extcolor.isNull()) {
02259         unsigned int number = extcolor.attribute("number").toInt(&ok);
02260         if (!ok)  { return false; }
02261         QDomNode color = extcolor.firstChild();
02262 
02263         for (unsigned int i=0; i<number; i++) {
02264             if (color.isNull()) {
02265                 kdDebug(35001) << "Some problems, there is less data than it should be!" << endl;
02266                 break;
02267             }
02268             QDomElement element = color.toElement();
02269             if ( !element.isNull()) {
02270                 if (element.hasAttribute( "name" )) {
02271                     m_params->ExtColor.setColor(i,QColor( element.attribute( "name" ) ));
02272                 }
02273                 color = color.nextSibling();
02274             }
02275         }
02276     }
02277 
02278     if ( !m_params->backgroundPixmapName.isNull() ) {
02279         m_params->backgroundPixmap.load( locate( "wallpaper",
02280                          m_params->backgroundPixmapName ));
02281         m_params->backgroundPixmapIsDirty = true;
02282     }
02283 #endif
02284     return true;
02285 }
02286 
02287 
02288 
02289 void  KChartPart::slotModified()
02290 {
02291     kdDebug(35001) << "slotModified called!" << endl;
02292 
02293     setModified(true);
02294 }
02295 
02296 
02297 bool KChartPart::showEmbedInitDialog(QWidget* /*parent*/)
02298 {
02299   // Don't show an embed dialog
02300   return true;
02301 }
02302 
02303 
02304 }  //KChart namespace
02305 
02306 #include "kchart_part.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys