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