/** * * Kalle Dalheimer */ #include // For basic data types characteristics. // For debugging #include using std::cout; using std::cerr; #include "kchart_part.h" #include "kchart_view.h" #include "kchart_factory.h" #include "kchartWizard.h" #include "kchart_params.h" #include "kdchart/KDChart.h" #include "kdchart/KDChartTable.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; // Some hardcoded data for a chart /* ----- set some data ----- */ // float a[6] = { 0.5, 0.09, 0.6, 0.85, 0.0, 0.90 }, // b[6] = { 1.9, 1.3, 0.6, 0.75, 0.1, -2.0 }; /* ----- X labels ----- */ // char *t[6] = { "Chicago", "New York", "L.A.", "Atlanta", "Paris, MD\n(USA) ", "London" }; /* ----- data set colors (RGB) ----- */ // TQColor sc[2] = { TQColor( 255, 128, 128 ), TQColor( 128, 128, 255 ) }; namespace KChart { KChartPart::KChartPart( TQWidget *parentWidget, const char *widgetName, TQObject* tqparent, const char* name, bool singleViewMode ) : KoChart::Part( parentWidget, widgetName, tqparent, name, singleViewMode ), m_params( 0 ), m_parentWidget( parentWidget ), m_rowLabels(), m_colLabels() { kdDebug(35001) << "Constructor started!" << endl; setInstance( KChartFactory::global(), false ); setTemplateType( "kchart_template" ); // Init some members that need it. { // Create the chart parameters and let the default be a bar chart // with 3D looks. m_params = new KChartParams( this ); m_params->setChartType( KChartParams::Bar ); m_params->setBarChartSubType( KChartParams::BarNormal ); m_params->setThreeDBars( true ); //Changed this to use columns rather than rows by default //because I believe that this is the more common format for //entering data (you can see this looking at the fact that //most spreadsheet packages allow far more rows than columns) //-- Robert Knight // Handle data in columns by default m_params->setDataDirection( KChartParams::DataColumns ); } (void)new WizardExt( this ); m_bCanChangeValue = true; // Display parameters m_displayData = m_currentData; // Set the size to minimal. initEmpty(); } KChartPart::~KChartPart() { //kdDebug(35001) << "Part is going to be destroyed now!!!" << endl; delete m_params; } // Reimplement KoDocument::initDoc() bool KChartPart::initDoc(InitDocFlags flags, TQWidget* parentWidget) { // Initialize the parameter set for this chart document #if 0 kdDebug(35001) << "================================================================" << endl; kdDebug(35001) << "InitDOC: flags = " << flags << endl; kdDebug(35001) << "================================================================" << endl; #endif TQString f; // Embedded documents are initially created like a normal empty // document. If this is in KSpread or another program where the // data is external then the document will be updated later on in // the creation process anyway. if (flags == KoDocument::InitDocEmbedded) { initEmpty(); return true; } // If we are supposed to create a new, empty document, then do so. if (flags == KoDocument::InitDocEmpty) { initEmpty(); return true; } KoTemplateChooseDia::ReturnType ret; KoTemplateChooseDia::DialogType dlgtype; // If we must create a new document, then only present templates // to the user, otherwise also present existing documents and // recent documents. if (flags == KoDocument::InitDocFileNew ) dlgtype = KoTemplateChooseDia::OnlyTemplates; else dlgtype = KoTemplateChooseDia::Everything; ret = KoTemplateChooseDia::choose( KChartFactory::global(), f, dlgtype, "kchart_template", parentWidget ); if ( ret == KoTemplateChooseDia::File ) { KURL url( f ); return openURL( url ); } else if ( ret == KoTemplateChooseDia::Empty ) { initEmpty(); return true; } else if ( ret == KoTemplateChooseDia::Template ) { //TODO: Activate this for KOffice 1.5/2.0 // if ( f.endsWith("/templates/chart/.source/BarChart.chrt") ) { // generateBarChartTemplate(); // return true; // } TQFileInfo fileInfo( f ); TQString fileName( fileInfo.dirPath( true ) + "/" + fileInfo.baseName() + ".chrt" ); resetURL(); bool ok = loadNativeFormat( fileName ); if ( !ok ) showLoadingErrorDialog(); setEmpty(); //initConfig(); return ok; } return false; } void KChartPart::initEmpty() { initNullChart(); resetURL(); setEmpty(); } // This method creates the simplest chart imaginable: // Data size 1x1, empty, no headers // void KChartPart::initNullChart() { // Fill cells with data if there is none. //kdDebug(35001) << "Initialize null chart." << endl; // Empty data. Note, we don't use (0,0) or (1,1) for the size // here, because otherwise KDChart won't draw anything m_currentData.expand(2, 2); m_params->setFirstRowAsLabel(false); m_params->setFirstColAsLabel(false); // Fill column and row labels. m_colLabels << TQString(""); m_rowLabels << TQString(""); setChartDefaults(); m_params->setDrawSolidExcessArrows(true); } void KChartPart::generateBarChartTemplate() { int col; int row; kdDebug()<<"KChartPart::initTestChart()\n"; // Fill cells with data if there is none. if (m_currentData.rows() == 0) { //kdDebug(35001) << "Initialize with some data!!!" << endl; m_currentData.expand( 4, 4 ); m_currentData.setUsedRows( 4 ); m_currentData.setUsedCols( 4 ); for (row = 0; row < 4; row++) { for (col = 0; col < 4; col++) { m_currentData.setCell(row, col, static_cast (row + col)); // Fill column label, but only on the first iteration. if (row == 0) { m_colLabels << i18n("Column %1").tqarg(col + 1); } } // Fill row label. m_rowLabels << i18n("Row %1").tqarg(row + 1); } } setChartDefaults(); // FIXME: Should this go into setChartDefaults()? m_params->setDrawSolidExcessArrows(true); } KoView* KChartPart::createViewInstance( TQWidget* tqparent, const char* name ) { return new KChartView( this, tqparent, name ); } // ================================================================ // Painting void KChartPart::paintContent( TQPainter& painter, const TQRect& rect, bool /*transparent*/, double /*zoomX*/, double /*zoomY*/ ) { int numDatasets; // If params is 0, initDoc() has not been called. Q_ASSERT( m_params != 0 ); KDChartAxisParams xAxisParms; xAxisParms = m_params->axisParams( KDChartAxisParams::AxisPosBottom ); // Handle data in rows or columns. // // This means getting row or column headers from the document and // set them as X axis labels or legend according to the current // setting. Also, transpose the data if it should be displayed in // columns instead of in rows. // Create the displayData table. numDatasets = createDisplayData(); // Create and set the axis labels and legend. TQStringList longLabels; TQStringList shortLabels; createLabelsAndLegend(longLabels, shortLabels); // Set the x axis labels. xAxisParms.setAxisLabelStringLists( &longLabels, &shortLabels ); m_params->setAxisParams(KDChartAxisParams::AxisPosBottom, xAxisParms); // Handle some types or subtypes of charts specially, notably: // - Bar charts with lines in them if ( m_params->chartType() == KChartParams::Bar) { if ( m_params->barNumLines() > 0 ) { // If this is a bar chart and the user wants a few lines in // it, we need to create an additional chart in the same // drawing area. // Specify that we want to have an additional chart. m_params->setAdditionalChartType( KDChartParams::Line ); const int numBarDatasets = numDatasets - m_params->barNumLines(); // Assign the datasets to the charts: DataEntry, from, to, chart# m_params->setChartSourceMode( KDChartParams::DataEntry, 0, numBarDatasets - 1, 0 ); // The bar chart m_params->setChartSourceMode( KDChartParams::DataEntry, numBarDatasets, numDatasets - 1, 1 ); // The line chart } else { // Otherwise we don't want any extra chart. m_params->setAdditionalChartType( KDChartParams::NoType ); } } // Ok, we have now created a data set for display, and params with // suitable legends and axis labels. Now start the real painting. // Handle transparency. // Wrong: this flickers; better do this as part of the double-buffering. //if ( !transparent ) // painter.eraseRect( rect ); // ## TODO: support zooming // Double-buffering if ( m_bufferPixmap.width() < rect.width() || m_bufferPixmap.height() < rect.height() ) { m_bufferPixmap.resize( rect.size() ); } TQPainter bufferPainter( &m_bufferPixmap ); // We only need to draw the document rectangle "rect". KDChart::paint( &bufferPainter, m_params, &m_displayData, 0, &rect ); // This is always the empty rect... // Shouldn't creating a TQPainter in a paintEvent set up clipping automatically? // I thought it did (DF) //const TQRect clipRect = painter.clipRegion().boundingRect(); //painter.drawPixmap( clipRect.topLeft(), m_bufferPixmap, clipRect ); painter.drawPixmap( 0, 0, m_bufferPixmap ); } // Create the data table m_displayData from m_currentData, taking into // account if the first row or line contains headers. The chart type // HiLo demands special handling. // // Return number of datasets. // // Note: While the current KD Chart 1.1.3 version is still expecting data // to be in rows, the upcoming KD Chart 2.0 release will be using // data in columns instead, to it will be matching KSpread's way. // -khz, 2005-11-15 // // FIXME: Rewrite so that we only copy data when necessary. // On the other hand, the next version of KDChart is able to // get data directly without storing it into a KDChartData // class first, so we might never need to. // int KChartPart::createDisplayData() { int rowOffset = 0; int colOffset = 0; int numDatasets = 0; if ( !canChangeValue() ) { if ( m_params->firstRowAsLabel() ) rowOffset++; if ( m_params->firstColAsLabel() ) colOffset++; } // After this sequence, m_DisplayData contains the data in the // correct transposition, and the X axis and the legend contain // the correct labels. TQVariant value1; TQVariant value2; int prop; if (m_params->dataDirection() == KChartParams::DataRows) { // Data is handled in rows. This is the way KDChart works also. numDatasets = m_currentData.usedRows() - rowOffset; m_displayData.expand( numDatasets, m_currentData.usedCols() - colOffset ); // Remove the first row and/or col if they are used for headers. for (uint row = rowOffset; row < m_currentData.usedRows(); row++) { for (uint col = colOffset; col < m_currentData.usedCols(); col++) { if ( m_currentData.cellContent( row, col, value1, value2, prop ) ) { m_displayData.setCell(row - rowOffset, col - colOffset, value1, value2); m_displayData.setProp(row - rowOffset, col - colOffset, prop); } } } } else { // Data is handled in columns. We will have to transpose // everything since KDChart wants its data in rows. // Resize displayData so that the transposed data has room. numDatasets = m_currentData.usedCols() - colOffset; m_displayData.expand( numDatasets, m_currentData.usedRows() - rowOffset ); // Copy data and transpose it. for (uint row = colOffset; row < m_currentData.usedCols(); row++) { for (uint col = rowOffset; col < m_currentData.usedRows(); col++) { if ( m_currentData.cellContent( col, row, value1, value2, prop ) ) { m_displayData.setCell(row - colOffset, col - rowOffset, value1, value2); m_displayData.setProp(row - colOffset, col - rowOffset, prop); } } } } // If this is a HiLo chart, we need to manually create the correct // values. This is not done by KDChart. // // Here we don't need to transpose, since we can start from the // newly generated displayData. if (m_params->chartType() == KChartParams::HiLo) { KDChartTableData tmpData = m_displayData; // Calculate the min, max, open and close values for each row. m_displayData.expand(tmpData.usedRows(), 4); for (uint row = 0; row < tmpData.usedRows(); row++) { double minVal = DBL_MAX; double maxVal = -DBL_MAX; // Calculate min and max for this row. // // Note that we have already taken care of different data // directions above. for (uint col = 0; col < tmpData.usedCols(); col++) { double data = tmpData.cellVal(row, col).toDouble(); if (data < minVal) minVal = data; if (data > maxVal) maxVal = data; } m_displayData.setCell(row, 0, minVal); // min m_displayData.setCell(row, 1, maxVal); // max m_displayData.setCell(row, 2, tmpData.cellVal(row, 0).toDouble()); // open m_displayData.setCell(row, 3, // close tmpData.cellVal(row, tmpData.usedCols() - 1).toDouble()); } } return numDatasets; } void KChartPart::createLabelsAndLegend( TQStringList &longLabels, TQStringList &shortLabels ) { longLabels.clear(); shortLabels.clear(); const uint dataColumnCount = m_currentData.cols(); const uint dataRowCount = m_currentData.rows(); const uint columnLabelCount = m_colLabels.count(); const uint rowLabelCount = m_rowLabels.count(); // Handle HiLo charts separately. if (m_params->chartType() == KChartParams::HiLo) { // FIXME: In a HiLo chart, the Legend should be the same as the // labels on the X Axis. Should we disable one of them? // Set the correct X axis labels and legend. longLabels.clear(); shortLabels.clear(); if (m_params->dataDirection() == KChartParams::DataRows) { // If data are in rows, then the X axis labels should be // taken from the row headers. for ( uint row = 0; row < dataRowCount ; row++ ) { TQString label = (row < rowLabelCount) ? m_rowLabels[row] : TQString(); longLabels << label; shortLabels << label.left( 3 ); } } else { // If data are in columns, then the X axis labels should // be taken from the column headers. for ( uint col = 0; col < dataColumnCount; col++ ) { TQString label = (col < columnLabelCount) ? m_colLabels[col] : TQString(); longLabels << m_colLabels[col]; shortLabels << m_colLabels[col].left( 3 ); } } } else if (m_params->dataDirection() == KChartParams::DataRows) { // Data is handled in rows. This is the way KDChart works also. // Set X axis labels from column headers. for ( uint col = 0; col < dataColumnCount; col++ ) { TQString label = (col < columnLabelCount) ? m_colLabels[col] : TQString(); longLabels << label; shortLabels << label.left( 3 ); } // Set legend from row headers. for ( uint row = 0; row < dataRowCount; row++ ) { TQString label = (row < rowLabelCount) ? m_rowLabels[row] : TQString(); m_params->setLegendText( row, label ); } } else { // Data is handled in columns. // Set X axis labels from row headers. for ( uint row = 0; row < dataRowCount; row++ ) { TQString label = (row < rowLabelCount) ? m_rowLabels[row] : TQString(); longLabels << label; shortLabels << label.left( 3 ); } // Set legend from column headers. for ( uint col = 0; col < dataColumnCount ; col++ ) { TQString label = (col < columnLabelCount) ? m_colLabels[col] : TQString(); m_params->setLegendText( col, label ); } } } // ================================================================ void KChartPart::analyzeHeaders() { #if 0 analyzeHeaders( m_currentData ); #else doSetData( m_currentData, m_params->firstRowAsLabel(), m_params->firstColAsLabel()); #endif } // This function sets the data from an external source. It is called, // for instance, when the chart is initialized from a spreadsheet in // KSpread. // void KChartPart::analyzeHeaders( const KDChartTableData& data ) { // FIXME(khz): replace this when automatic string detection works in KDChart // Does the top/left cell contain a string? bool isStringTopLeft = (data.cellVal( 0, 0 ).type() == TQVariant::String); // Does the first row (without first cell) contain only strings? bool isStringFirstRow = true; for ( uint col = 1; isStringFirstRow && col < data.cols(); col++ ) { isStringFirstRow = (data.cellVal( 0, col ).type() == TQVariant::String); } // Just in case, we only have 1 row, we never use it for label text. // This prevents a crash. // // FIXME: Wonder if this is still true for KDChart 1.1.3 / iw // Disabling... #if 1 if ( data.rows() == 1 ) isStringFirstRow = false; #endif // Does the first column (without first cell) contain only strings? bool isStringFirstCol = true; for ( uint row = 1; isStringFirstCol && row < data.rows(); row++ ) { isStringFirstCol = (data.cellVal( row, 0 ).type() == TQVariant::String); } // Just in case, we only have 1 column, we never use it for axis // label text => prevents crash. #if 1 if ( data.cols() == 1 ) isStringFirstRow = FALSE; #endif bool hasColHeader = false; bool hasRowHeader = false; // Let's check if we have a full axis label text column if ( isStringFirstCol && isStringTopLeft || isStringFirstCol && isStringFirstRow ) hasColHeader = true; // Let's check if we have a full label text row. if ( isStringFirstRow && isStringTopLeft || isStringFirstCol && isStringFirstRow ) hasRowHeader = true; m_params->setFirstRowAsLabel( hasRowHeader ); m_params->setFirstColAsLabel( hasColHeader ); doSetData(data, hasRowHeader, hasColHeader); } void KChartPart::doSetData( const KDChartTableData& data, bool firstRowHeader, bool firstColHeader ) { uint rowStart = 0; uint colStart = 0; uint col; uint row; // From this point, we know that the labels and legend are going // to be taken from the data if firstRowHeader or firstColheader // is true. if (firstRowHeader) rowStart = 1; if (firstColHeader) colStart = 1; // Generate m_rowlabels from the column headers if applicable. m_rowLabels.clear(); if ( firstColHeader ) { for( row = rowStart; row < data.rows(); row++ ) { m_rowLabels << data.cellVal( row, 0 ).toString(); } } else { for( row = rowStart; row < data.rows(); row++ ) m_rowLabels << ""; // FIXME: Check what this does, and if we don't have to check // the data order (rows / cols). m_params->setLegendSource( KDChartParams::LegendAutomatic ); } // Generate X labels from the row headers if applicable m_colLabels.clear(); if ( firstRowHeader ) { for( col = colStart; col < data.cols(); col++ ) { m_colLabels << data.cellVal( 0, col ).toString(); } } else { for( col = colStart; col < data.cols(); col++ ) m_colLabels << ""; } // Doesn't hurt if data == m_currentData, but necessary if not. m_currentData = data; //setChartDefaults(); emit docChanged(); } void KChartPart::resizeData( int rows, int cols ) { m_currentData.expand( rows, cols ); m_currentData.setUsedRows( rows ); m_currentData.setUsedCols( cols ); } void KChartPart::setCellData( int row, int column, const TQVariant &val) { m_currentData.setCell( row, column, val ); } bool KChartPart::showWizard( TQString &dataArea ) { KChartWizard *wizard = new KChartWizard( this, m_parentWidget, "wizard" ); connect( wizard, TQT_SIGNAL(finished()), this, TQT_SLOT(slotModified()) ); wizard->setDataArea( dataArea ); bool ret = wizard->exec(); delete wizard; return ret; } void KChartPart::initLabelAndLegend() { // Labels and legends are automatically initialized to reasonable // default values in KDChart } // Set up some values for the chart Axis, that are not well chosen by // default by KDChart. // void KChartPart::setChartDefaults() { // // Settings for the Y axis. // KDChartAxisParams yAxis; yAxis = m_params->axisParams( KDChartAxisParams::AxisPosLeft ); // decimal symbol and thousands separator yAxis.setAxisLabelsRadix( KGlobal::locale()->decimalSymbol(), KGlobal::locale()->thousandsSeparator() ); m_params->setAxisParams( KDChartAxisParams::AxisPosLeft, yAxis ); // // Settings for the X axis. // KDChartAxisParams xAxis; xAxis = m_params->axisParams( KDChartAxisParams::AxisPosBottom ); // These two shouldn't be necessary to set. xAxis.setAxisFirstLabelText(); xAxis.setAxisLastLabelText(); m_params->setAxisParams( KDChartAxisParams::AxisPosBottom, xAxis ); // Other parameters for various things. m_params->setLineColor(); // Setting the background layer. KDFrame frame; frame.setBackground( TQBrush( TQColor( 230, 222, 222 ) ) ); m_params->setFrame( KDChartEnums::AreaInnermost, frame, 0, 0, 0, 0 ); } // ================================================================ // Loading and Storing // ---------------------------------------------------------------- // Save and Load program configuration void KChartPart::loadConfig( KConfig *conf ) { conf->setGroup("ChartParameters"); // TODO: the fonts // PENDING(kalle) Put the applicable ones of these back in // TQFont tempfont; // tempfont = conf->readFontEntry("titlefont", &titlefont); // setTitleFont(tempfont); // tempfont = conf->readFontEntry("ytitlefont", &ytitlefont); // setYTitleFont(tempfont); // tempfont = conf->readFontEntry("xtitlefont", &xtitlefont); // setXTitleFont(tempfont); // tempfont = conf->readFontEntry("yaxisfont", &yaxisfont); // setYAxisFont(tempfont); // tempfont = conf->readFontEntry("xaxisfont", &xaxisfont); // setXAxisFont(tempfont); // tempfont = conf->readFontEntry("labelfont", &labelfont); // setLabelFont(tempfont); // tempfont = conf->readFontEntry("annotationfont", &annotationfont); // setAnnotationFont(tempfont); // ylabel_fmt = conf->readEntry("ylabel_fmt", ylabel_fmt ); // ylabel2_fmt = conf->readEntry("ylabel2_fmt", ylabel2_fmt); // xlabel_spacing = conf->readNumEntry("xlabel_spacing"); // ylabel_density = conf->readNumEntry("ylabel_density", ylabel_density); // requested_ymin = conf->readDoubleNumEntry("requested_ymin", requested_ymin); // requested_ymax = conf->readDoubleNumEntry("requested_ymax", requested_ymax ); // requested_yinterval = conf->readDoubleNumEntry("requested_yinterval", // requested_yinterval); // shelf = conf->readBoolEntry("shelf", shelf); // grid = conf->readBoolEntry("grid", grid); // xaxis = conf->readBoolEntry("xaxis", xaxis); // yaxis = conf->readBoolEntry("yaxis", yaxis); // yaxis2 = conf->readBoolEntry("yaxis2", yaxis); // llabel = conf->readBoolEntry("llabel", llabel); // yval_style = conf->readNumEntry("yval_style", yval_style); // stack_type = (KChartStackType)conf->readNumEntry("stack_type", stack_type); m_params->setLineMarker(conf->readBoolEntry("lineMarker", m_params->lineMarker())); m_params->setThreeDBarDepth( conf->readDoubleNumEntry("_3d_depth", m_params->threeDBarDepth() ) ); m_params->setThreeDBarAngle( conf->readNumEntry( "_3d_angle", m_params->threeDBarAngle() ) ); KDChartAxisParams leftparams; leftparams = m_params->axisParams( KDChartAxisParams::AxisPosLeft ); KDChartAxisParams rightparams; rightparams = m_params->axisParams( KDChartAxisParams::AxisPosRight ); KDChartAxisParams bottomparams; bottomparams = m_params->axisParams( KDChartAxisParams::AxisPosBottom ); bottomparams.setAxisLineColor( conf->readColorEntry( "XTitleColor", 0 ) ); leftparams.setAxisLineColor( conf->readColorEntry( "YTitleColor", 0 ) ); rightparams.setAxisLineColor( conf->readColorEntry( "YTitle2Color", 0 ) ); bottomparams.setAxisLabelsColor( conf->readColorEntry( "XLabelColor", 0 ) ); leftparams.setAxisLabelsColor( conf->readColorEntry( "YLabelColor", 0 ) ); rightparams.setAxisLabelsColor( conf->readColorEntry( "YLabel2Color", 0 ) ); leftparams.setAxisGridColor( conf->readColorEntry( "GridColor", 0 ) ); m_params->setOutlineDataColor( conf->readColorEntry( "LineColor", 0 ) ); m_params->setAxisParams( KDChartAxisParams::AxisPosLeft, leftparams ); m_params->setAxisParams( KDChartAxisParams::AxisPosRight, rightparams ); m_params->setAxisParams( KDChartAxisParams::AxisPosBottom, bottomparams ); // hlc_style = (KChartHLCStyle)conf->readNumEntry("hlc_style", hlc_style); // hlc_cap_width = conf->readNumEntry("hlc_cap_width", hlc_cap_width); // // TODO: Annotation font // num_scatter_pts = conf->readNumEntry("num_scatter_pts", num_scatter_pts); // // TODO: Scatter type // thumbnail = conf->readBoolEntry("thumbnail", thumbnail); // thumblabel = conf->readEntry("thumblabel", thumblabel); // border = conf->readBoolEntry("border", border); // BGColor = conf->readColorEntry("BGColor", &BGColor); // PlotColor = conf->readColorEntry("PlotColor", &PlotColor); // VolColor = conf->readColorEntry("VolColor", &VolColor); // EdgeColor = conf->readColorEntry("EdgeColor", &EdgeColor); // loadColorArray(conf, &SetColor, "SetColor"); // loadColorArray(conf, &ExtColor, "ExtColor"); // loadColorArray(conf, &ExtVolColor, "ExtVolColor"); // transparent_bg = conf->readBoolEntry("transparent_bg", transparent_bg); // // TODO: explode, missing // percent_labels = (KChartPercentType)conf->readNumEntry("percent_labels", // percent_labels); // label_dist = conf->readNumEntry("label_dist", label_dist); // label_line = conf->readBoolEntry("label_line", label_line); m_params->setChartType( (KChartParams::ChartType)conf->readNumEntry( "type", m_params->chartType() ) ); // other_threshold = conf->readNumEntry("other_threshold", other_threshold); // backgroundPixmapName = conf->readPathEntry( "backgroundPixmapName" ); // if( !backgroundPixmapName.isNull() ) { // backgroundPixmap.load( locate( "wallpaper", backgroundPixmapName )); // backgroundPixmapIsDirty = true; // } else // backgroundPixmapIsDirty = false; // backgroundPixmapScaled = conf->readBoolEntry( "backgroundPixmapScaled", true ); // backgroundPixmapCentered = conf->readBoolEntry( "backgroundPixmapCentered", true ); // backgroundPixmapIntensity = conf->readDoubleNumEntry( "backgroundPixmapIntensity", 0.25 ); } void KChartPart::defaultConfig( ) { delete m_params; m_params = new KChartParams( this ); setChartDefaults(); } void KChartPart::saveConfig( KConfig *conf ) { conf->setGroup("ChartParameters"); // PENDING(kalle) Put some of these back in // the fonts // conf->writeEntry("titlefont", titlefont); // conf->writeEntry("ytitlefont", ytitlefont); // conf->writeEntry("xtitlefont", xtitlefont); // conf->writeEntry("yaxisfont", yaxisfont); // conf->writeEntry("xaxisfont", xaxisfont); // conf->writeEntry("labelfont", labelfont); // conf->writeEntry("ylabel_fmt", ylabel_fmt); // conf->writeEntry("ylabel2_fmt", ylabel2_fmt); // conf->writeEntry("xlabel_spacing", xlabel_spacing); // conf->writeEntry("ylabel_density", ylabel_density); // conf->writeEntry("requested_ymin", requested_ymin); // conf->writeEntry("requested_ymax", requested_ymax); // conf->writeEntry("requested_yinterval", requested_yinterval); // conf->writeEntry("shelf", shelf); // conf->writeEntry("grid", grid ); // conf->writeEntry("xaxis", xaxis); // conf->writeEntry("yaxis", yaxis); // conf->writeEntry("yaxis2", yaxis2); // conf->writeEntry("llabel", llabel); // conf->writeEntry("yval_style", yval_style ); // conf->writeEntry("stack_type", (int)stack_type); conf->writeEntry( "_3d_depth", m_params->threeDBarDepth() ); conf->writeEntry( "_3d_angle", m_params->threeDBarAngle() ); KDChartAxisParams leftparams; leftparams = m_params->axisParams( KDChartAxisParams::AxisPosLeft ); KDChartAxisParams rightparams; rightparams = m_params->axisParams( KDChartAxisParams::AxisPosRight ); KDChartAxisParams bottomparams; bottomparams = m_params->axisParams( KDChartAxisParams::AxisPosBottom ); conf->writeEntry( "LineColor", m_params->outlineDataColor() ); conf->writeEntry( "XTitleColor", bottomparams.axisLineColor() ); conf->writeEntry( "YTitleColor", leftparams.axisLineColor() ); conf->writeEntry( "YTitle2Color", rightparams.axisLineColor() ); conf->writeEntry( "XLabelColor", bottomparams.axisLabelsColor() ); conf->writeEntry( "YLabelColor", leftparams.axisLabelsColor() ); conf->writeEntry( "YLabel2Color", rightparams.axisLabelsColor() ); conf->writeEntry( "GridColor", leftparams.axisGridColor() ); // conf->writeEntry("hlc_style", (int)hlc_style); // conf->writeEntry("hlc_cap_width", hlc_cap_width ); // // TODO: Annotation type!!! // conf->writeEntry("annotationfont", annotationfont); // conf->writeEntry("num_scatter_pts", num_scatter_pts); // // TODO: Scatter type!!! // conf->writeEntry("thumbnail", thumbnail); // conf->writeEntry("thumblabel", thumblabel); // conf->writeEntry("thumbval", thumbval); // conf->writeEntry("border", border); // conf->writeEntry("BGColor", BGColor); // conf->writeEntry("PlotColor", PlotColor); // conf->writeEntry("VolColor", VolColor); // conf->writeEntry("EdgeColor", EdgeColor); // saveColorArray(conf, &SetColor, "SetColor"); // saveColorArray(conf, &ExtColor, "ExtColor"); // saveColorArray(conf, &ExtVolColor, "ExtVolColor"); // conf->writeEntry("transparent_bg", transparent_bg); // // TODO: explode, missing // conf->writeEntry("percent_labels",(int) percent_labels ); // conf->writeEntry("label_dist", label_dist); // conf->writeEntry("label_line", label_line); conf->writeEntry( "type", (int) m_params->chartType() ); // conf->writeEntry("other_threshold", other_threshold); // background pixmap stuff // if( !backgroundPixmapName.isNull() ) // conf->writePathEntry( "backgroundPixmapName", backgroundPixmapName ); // conf->writeEntry( "backgroundPixmapIsDirty", backgroundPixmapIsDirty ); // conf->writeEntry( "backgroundPixmapScaled", backgroundPixmapScaled ); // conf->writeEntry( "backgroundPixmapCentered", backgroundPixmapCentered ); // conf->writeEntry( "backgroundPixmapIntensity", backgroundPixmapIntensity ); conf->writeEntry( "lineMarker", (int) m_params->lineMarker()); } // ---------------------------------------------------------------- // Save and Load OpenDocument file format bool KChartPart::loadOasis( const TQDomDocument& doc, KoOasisStyles& oasisStyles, const TQDomDocument& /*settings*/, KoStore *store ) { kdDebug(35001) << "kchart loadOasis called" << endl; // Set some sensible defaults. setChartDefaults(); TQDomElement content = doc.documentElement(); TQDomElement bodyElem ( KoDom::namedItemNS( content, KoXmlNS::office, "body" ) ); if ( bodyElem.isNull() ) { kdError(32001) << "No office:body found!" << endl; setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No office:body tag found." ) ); return false; } // Get the office:chart element. TQDomElement officeChartElem = KoDom::namedItemNS( bodyElem, KoXmlNS::office, "chart" ); if ( officeChartElem.isNull() ) { kdError(32001) << "No office:chart found!" << endl; TQDomElement childElem; TQString localName; forEachElement( childElem, bodyElem ) { localName = childElem.localName(); } if ( localName.isEmpty() ) setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No tag found inside office:body." ) ); else setErrorMessage( i18n( "This document is not a chart, but %1. Please try opening it with the appropriate application." ).tqarg( KoDocument::tagNameToDocumentType( localName ) ) ); return false; } TQDomElement chartElem = KoDom::namedItemNS( officeChartElem, KoXmlNS::chart, "chart" ); if ( chartElem.isNull() ) { setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No chart:chart tag found." ) ); return false; } // Get the loading context and stylestack from the styles. KoOasisLoadingContext loadingContext( this, oasisStyles, store ); //KoStyleStack &styleStack = loadingContext.styleStack(); #if 0 // Example code!! // load chart properties into the stylestack. styleStack.save(); styleStack.setTypeProperties( "chart" ); // load chart properties loadingContext.fillStyleStack( chartElem, KoXmlNS::chart, "style-name" ); const TQString fillColor = styleStack.attributeNS( KoXmlNS::draw, "fill-color" ); kdDebug() << "fillColor=" << fillColor << endl; styleStack.restore(); #endif // Load chart parameters, most of these are stored in the // chart:plot-area element within chart:chart. TQString errorMessage; bool ok = m_params->loadOasis( chartElem, loadingContext, errorMessage, store); if ( !ok ) { setErrorMessage( errorMessage ); return false; } // TODO Load data direction (see loadAuxiliary) // Load the data table. TQDomElement tableElem = KoDom::namedItemNS( chartElem, KoXmlNS::table, "table" ); if ( !tableElem.isNull() ) { ok = loadOasisData( tableElem ); if ( !ok ) return false; // TODO setErrorMessage } return true; } bool KChartPart::loadOasisData( const TQDomElement& tableElem ) { int numberHeaderColumns = 0; TQDomElement tableHeaderColumns = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-header-columns" ); TQDomElement elem; forEachElement( elem, tableHeaderColumns ) { if ( elem.localName() == "table-column" ) { int repeated = elem.attributeNS( KoXmlNS::table, "number-columns-repeated", TQString() ).toInt(); numberHeaderColumns += TQMAX( 1, repeated ); } } // With 0 you get no titles, and with more than 1 we ignore the others. Q_ASSERT( numberHeaderColumns == 1 ); int numberDataColumns = 0; TQDomElement tableColumns = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-columns" ); forEachElement( elem, tableColumns ) { if ( elem.localName() == "table-column" ) { int repeated = elem.attributeNS( KoXmlNS::table, "number-columns-repeated", TQString() ).toInt(); numberDataColumns += TQMAX( 1, repeated ); } } // Parse table-header-rows for the column names. m_colLabels.clear(); TQDomElement tableHeaderRows = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-header-rows" ); if ( tableHeaderRows.isNull() ) kdWarning(35001) << "No table-header-rows element found!" << endl; TQDomElement tableHeaderRow = KoDom::namedItemNS( tableHeaderRows, KoXmlNS::table, "table-row" ); if ( tableHeaderRow.isNull() ) kdWarning(35001) << "No table-row inside table-header-rows!" << endl; int cellNum = 0; forEachElement( elem, tableHeaderRow ) { if ( elem.localName() == "table-cell" ) { ++cellNum; if ( cellNum > numberHeaderColumns ) { TQDomElement pElem = KoDom::namedItemNS( elem, KoXmlNS::text, "p" ); m_colLabels.append( pElem.text() ); } } } numberDataColumns = TQMAX( numberDataColumns, cellNum - numberHeaderColumns ); if ( (int)m_colLabels.count() != numberDataColumns ) kdWarning(35001) << "Got " << m_colLabels.count() << " column titles, expected " << numberDataColumns << endl; // Get the number of rows, and read row labels int numberDataRows = 0; TQDomElement tableRows = KoDom::namedItemNS( tableElem, KoXmlNS::table, "table-rows" ); m_rowLabels.clear(); forEachElement( elem, tableRows ) { if ( elem.localName() == "table-row" ) { int repeated = elem.attributeNS( KoXmlNS::table, "number-rows-repeated", TQString() ).toInt(); Q_ASSERT( repeated <= 1 ); // we don't handle yet the case where data rows are repeated (can this really happen?) numberDataRows += TQMAX( 1, repeated ); if ( numberHeaderColumns > 0 ) { TQDomElement firstCell = KoDom::namedItemNS( elem, KoXmlNS::table, "table-cell" ); TQDomElement pElem = KoDom::namedItemNS( firstCell, KoXmlNS::text, "p" ); m_rowLabels.append( pElem.text() ); } } } kdDebug(35001) << "numberHeaderColumns=" << numberHeaderColumns << " numberDataColumns=" << numberDataColumns << " numberDataRows=" << numberDataRows << endl; if ( (int)m_rowLabels.count() != numberDataRows) kdWarning(35001) << "Got " << m_rowLabels.count() << " row labels, expected " << numberDataRows << endl; m_currentData.expand( numberDataRows, numberDataColumns ); m_currentData.setUsedCols( numberDataColumns ); m_currentData.setUsedRows( numberDataRows ); // Now really load the cells. int row = 0; TQDomElement rowElem; forEachElement( rowElem, tableRows ) { if ( rowElem.localName() == "table-row" ) { int col = 0; int cellNum = 0; TQDomElement cellElem; forEachElement( cellElem, rowElem ) { if ( cellElem.localName() == "table-cell" ) { ++cellNum; if ( cellNum > numberHeaderColumns ) { TQString valueType = cellElem.attributeNS( KoXmlNS::office, "value-type", TQString() ); if ( valueType != "float" ) kdWarning(35001) << "Don't know how to handle value-type " << valueType << endl; else { TQString value = cellElem.attributeNS( KoXmlNS::office, "value", TQString() ); double val = value.toDouble(); m_currentData.setCell( row, col, val ); } ++col; } } } ++row; } } return true; } bool KChartPart::saveOasis( KoStore* store, KoXmlWriter* manifestWriter ) { manifestWriter->addManifestEntry( "content.xml", "text/xml" ); KoOasisStore oasisStore( store ); KoXmlWriter* contentWriter = oasisStore.contentWriter(); if ( !contentWriter ) return false; KoGenStyles mainStyles; KoXmlWriter* bodyWriter = oasisStore.bodyWriter(); bodyWriter->startElement( "office:body" ); bodyWriter->startElement( "office:chart" ); bodyWriter->startElement( "chart:chart" ); // Indent to indicate that this is inside some tags. { // Saves chart class, title, legend, plot-area m_params->saveOasis( bodyWriter, mainStyles ); // Save the data table. saveOasisData( bodyWriter, mainStyles ); } bodyWriter->endElement(); // chart:chart bodyWriter->endElement(); // office:chart bodyWriter->endElement(); // office:body contentWriter->startElement( "office:automatic-styles" ); writeAutomaticStyles( *contentWriter, mainStyles ); contentWriter->endElement(); // office:automatic-styles oasisStore.closeContentWriter(); // Done with content.xml #if 0 if ( !store->open( "styles.xml" ) ) return false; manifestWriter->addManifestEntry( "styles.xml", "text/xml" ); saveOasisDocumentStyles( store, mainStyles, savingContext, saveFlag, headerFooterContent ); if ( !store->close() ) // done with styles.xml return false; #endif return true; } void KChartPart::saveOasisData( KoXmlWriter* bodyWriter, KoGenStyles& mainStyles ) const { Q_UNUSED( mainStyles ); const int cols = m_currentData.usedCols() ? TQMIN(m_currentData.usedCols(), m_currentData.cols()) : m_currentData.cols(); const int rows = m_currentData.usedRows() ? TQMIN(m_currentData.usedRows(), m_currentData.rows()) : m_currentData.rows(); bodyWriter->startElement( "table:table" ); bodyWriter->addAttribute( "table:name", "local-table" ); // Exactly one header column, always. bodyWriter->startElement( "table:table-header-columns" ); bodyWriter->startElement( "table:table-column" ); bodyWriter->endElement(); // table:table-column bodyWriter->endElement(); // table:table-header-columns // Then "cols" columns bodyWriter->startElement( "table:table-columns" ); bodyWriter->startElement( "table:table-column" ); bodyWriter->addAttribute( "table:number-columns-repeated", cols ); bodyWriter->endElement(); // table:table-column bodyWriter->endElement(); // table:table-columns // Exactly one header row, always. bodyWriter->startElement( "table:table-header-rows" ); bodyWriter->startElement( "table:table-row" ); // The first column in header row is just the header column - no title needed bodyWriter->startElement( "table:table-cell" ); bodyWriter->addAttribute( "office:value-type", "string" ); bodyWriter->startElement( "text:p" ); bodyWriter->endElement(); // text:p bodyWriter->endElement(); // table:table-cell // Save column labels in the first header row, for instance: // // Column 1 // TQStringList::const_iterator colLabelIt = m_colLabels.begin(); for ( int col = 0; col < cols ; ++col ) { if ( colLabelIt != m_colLabels.end() ) { bodyWriter->startElement( "table:table-cell" ); bodyWriter->addAttribute( "office:value-type", "string" ); bodyWriter->startElement( "text:p" ); bodyWriter->addTextNode( *colLabelIt ); bodyWriter->endElement(); // text:p bodyWriter->endElement(); // table:table-cell ++colLabelIt; } } bodyWriter->endElement(); // table:table-row bodyWriter->endElement(); // table:table-header-rows bodyWriter->startElement( "table:table-rows" ); TQStringList::const_iterator rowLabelIt = m_rowLabels.begin(); for ( int row = 0; row < rows ; ++row ) { bodyWriter->startElement( "table:table-row" ); if ( rowLabelIt != m_rowLabels.end() ) { // Save row labels, similar to column labels bodyWriter->startElement( "table:table-cell" ); bodyWriter->addAttribute( "office:value-type", "string" ); bodyWriter->startElement( "text:p" ); bodyWriter->addTextNode( *rowLabelIt ); bodyWriter->endElement(); // text:p bodyWriter->endElement(); // table:table-cell ++rowLabelIt; } for ( int col = 0; col < cols; ++col ) { TQVariant value( m_currentData.cellVal( row, col ) ); TQString valType; TQString valStr; switch ( value.type() ) { case TQVariant::Invalid: break; case TQVariant::String: valType = "string"; valStr = value.toString(); break; case TQVariant::Double: valType = "float"; valStr = TQString::number( value.toDouble(), 'g', DBL_DIG ); break; case TQVariant::DateTime: valType = "date"; valStr = ""; /* like in saveXML, but why? */ break; default: { kdDebug(35001) << "ERROR: cell " << row << "," << col << " has unknown type." << endl; } } // Add the value type and the string to the XML tree. bodyWriter->startElement( "table:table-cell" ); if ( !valType.isEmpty() ) { bodyWriter->addAttribute( "office:value-type", valType ); if ( value.type() == TQVariant::Double ) bodyWriter->addAttribute( "office:value", valStr ); bodyWriter->startElement( "text:p" ); bodyWriter->addTextNode( valStr ); bodyWriter->endElement(); // text:p } bodyWriter->endElement(); // table:table-cell } bodyWriter->endElement(); // table:table-row } bodyWriter->endElement(); // table:table-rows bodyWriter->endElement(); // table:table } void KChartPart::writeAutomaticStyles( KoXmlWriter& contentWriter, KoGenStyles& mainStyles ) const { TQValueList styles = mainStyles.styles( KoGenStyle::STYLE_AUTO ); TQValueList::const_iterator it = styles.begin(); for ( ; it != styles.end() ; ++it ) { (*it).style->writeStyle( &contentWriter, mainStyles, "style:style", (*it).name, "style:chart-properties" ); } } // ---------------------------------------------------------------- // Save and Load old KChart file format TQDomDocument KChartPart::saveXML() { TQDomElement tmpElem; //kdDebug(35001) << "kchart saveXML called" << endl; // The biggest part of the saving is done by KDChart itself, so we // don't have to do it. TQDomDocument doc = m_params->saveXML( false ); // ---------------------------------------------------------------- // The rest of the saving has to be done by us. TQDomElement docRoot = doc.documentElement(); // Save auxiliary data. TQDomElement aux = doc.createElement( "KChartAuxiliary" ); docRoot.appendChild( aux ); // The data direction (rows/columns). tmpElem = doc.createElement( "direction" ); tmpElem.setAttribute( "value", (int) m_params->dataDirection() ); aux.appendChild( tmpElem ); tmpElem = doc.createElement( "dataaslabel" ); tmpElem.setAttribute( "firstrow", m_params->firstRowAsLabel() ? "true" : "false" ); tmpElem.setAttribute( "firstcol", m_params->firstColAsLabel() ? "true" : "false" ); aux.appendChild( tmpElem ); tmpElem = doc.createElement( "barnumlines" ); tmpElem.setAttribute( "value", (int) m_params->barNumLines() ); aux.appendChild( tmpElem ); // Save the data values. TQDomElement data = doc.createElement( "data" ); docRoot.appendChild( data ); int cols = m_currentData.usedCols() ? TQMIN(m_currentData.usedCols(), m_currentData.cols()) : m_currentData.cols(); int rows = m_currentData.usedRows() ? TQMIN(m_currentData.usedRows(), m_currentData.rows()) : m_currentData.rows(); data.setAttribute( "cols", cols ); data.setAttribute( "rows", rows ); kdDebug(35001) << " writing " << cols << "," << rows << " (cols,rows)." << endl; for (int i=0; i!=rows; ++i) { for (int j=0; j!=cols; ++j) { TQDomElement e = doc.createElement( "cell" ); data.appendChild( e ); TQString valType; TQVariant value( m_currentData.cellVal( i,j ) ); switch ( value.type() ) { case TQVariant::Invalid: valType = "NoValue"; break; case TQVariant::String: valType = "String"; break; case TQVariant::Double: valType = "Double"; break; case TQVariant::DateTime: valType = "DateTime"; break; default: { valType = "(unknown)"; kdDebug(35001) << "ERROR: cell " << i << "," << j << " has unknown type." << endl; } } e.setAttribute( "valType", valType ); //kdDebug(35001) << " cell " << i << "," << j // << " saved with type '" << valType << "'." << endl; switch ( value.type() ) { case TQVariant::String: e.setAttribute( "value", value.toString() ); break; case TQVariant::Double: e.setAttribute( "value", TQString::number( value.toDouble() ) ); break; case TQVariant::DateTime:e.setAttribute( "value", "" ); break; default: { e.setAttribute( "value", "" ); if( TQVariant::Invalid != value.type() ) kdDebug(35001) << "ERROR: cell " << i << "," << j << " has unknown type." << endl; } } } } return doc; } bool KChartPart::loadXML( TQIODevice*, const TQDomDocument& doc ) { kdDebug(35001) << "kchart loadXML called" << endl; // Set some sensible defaults. setChartDefaults(); // First try to load the KDChart parameters. bool result = m_params->loadXML( doc ); // If went well, try to load the auxiliary data and the data... if (result) { result = loadAuxiliary(doc) && loadData( doc, m_currentData ); } else { // ...but if it did, try to load the old XML format. result = loadOldXML( doc ); } // If everything is OK, then get the headers from the KDChart parameters. if (result) { TQStringList legendLabels; KDChartAxisParams params; params = m_params->axisParams( KDChartAxisParams::AxisPosBottom ); // Get the legend. TQString str; uint index = 0; while ((str = m_params->legendText(index++)) != TQString()) legendLabels << str; if (m_params->dataDirection() == KChartParams::DataRows) { m_colLabels = params.axisLabelStringList(); m_rowLabels = legendLabels; } else { m_colLabels = legendLabels; m_rowLabels = params.axisLabelStringList(); } } m_params->setDrawSolidExcessArrows(true); return result; } // Load the auxiliary data. // // Currently, that means the data direction. // bool KChartPart::loadAuxiliary( const TQDomDocument& doc ) { TQDomElement chart = doc.documentElement(); TQDomElement aux = chart.namedItem("KChartAuxiliary").toElement(); // Older XML files might be missing this section. That is OK; the // defaults will be used. if (aux.isNull()) return true; TQDomNode node = aux.firstChild(); // If the aux section exists, it should contain data. while (!node.isNull()) { TQDomElement e = node.toElement(); if (e.isNull()) { // FIXME: Should this be regarded as an error? node = node.nextSibling(); continue; } // Check for direction if ( e.tagName() == "direction" ) { if ( e.hasAttribute("value") ) { bool ok; // Read the direction. On failure, use the default. int dir = e.attribute("value").toInt(&ok); if ( !ok ) dir = (int) KChartParams::DataColumns; //kdDebug(35001) << "Got aux value \"direction\": " << dir << endl; m_params->setDataDirection( (KChartParams::DataDirection) dir ); } else { kdDebug(35001) << "Error in direction tag." << endl; } } // Check for first row / col as label else if ( e.tagName() == "dataaslabel" ) { TQString val; if ( e.hasAttribute("firstrow") ) { // Read the direction. On failure, use the default. val = e.attribute("firstrow"); if ( val == "true" ) m_params->setFirstRowAsLabel( true ); else m_params->setFirstRowAsLabel( false ); } else { kdDebug(35001) << "Error in barnumlines tag." << endl; m_params->setFirstRowAsLabel( false ); } if ( e.hasAttribute("firstcol") ) { // Read the direction. On failure, use the default. val = e.attribute("firstcol"); if ( val == "true" ) m_params->setFirstColAsLabel( true ); else m_params->setFirstColAsLabel( false ); } else { kdDebug(35001) << "Error in barnumlines tag." << endl; m_params->setFirstColAsLabel( false ); } } // Check for number of lines in a bar chart. else if ( e.tagName() == "barnumlines" ) { if ( e.hasAttribute("value") ) { bool ok; // Read the number of lines. On failure, use the default. int barNumLines = e.attribute("value").toInt(&ok); if ( !ok ) barNumLines = 0; //kdDebug(35001) << "Got aux value \"barnumlines\": " // << barNumLines << endl; m_params->setBarNumLines( barNumLines ); } else { kdDebug(35001) << "Error in barnumlines tag." << endl; } } #if 0 // Expand with more auxiliary types when needed. else if ( e.tagName() == "..." ) { } and so on... #endif node = node.nextSibling(); } return true; } bool KChartPart::loadData( const TQDomDocument& doc, KDChartTableData& m_currentData ) { kdDebug(35001) << "kchart loadData called" << endl; TQDomElement chart = doc.documentElement(); TQDomElement data = chart.namedItem("data").toElement(); bool ok; int cols = data.attribute("cols").toInt(&ok); kdDebug(35001) << "cols readed as:" << cols << endl; if ( !ok ){ return false; } int rows = data.attribute("rows").toInt(&ok); if ( !ok ){ return false; } kdDebug(35001) << rows << " x " << cols << endl; m_currentData.expand(rows, cols); m_currentData.setUsedCols( cols ); m_currentData.setUsedRows( rows ); kdDebug(35001) << "Expanded!" << endl; TQDomNode n = data.firstChild(); //TQArray tmpExp(rows*cols); //TQArray tmpMissing(rows*cols); for (int i=0; i!=rows; i++) { for (int j=0; j!=cols; j++) { if (n.isNull()) { kdDebug(35001) << "Some problems, there is less data than it should be!" << endl; break; } TQDomElement e = n.toElement(); if ( !e.isNull() && e.tagName() == "cell" ) { // add the cell to the corresponding place... TQVariant t; if ( e.hasAttribute("value") && e.hasAttribute("valType") ) { TQString valueType = e.attribute("valType").lower(); if ( "string" == valueType ) { t = e.attribute("value"); } else if ( "double" == valueType ) { bool bOk; double val = e.attribute("value").toDouble(&bOk); if ( !bOk ) val = 0.0; t = val; /* } else if ( "datetime" == valueType ) { t = . . . */ } else { t.clear(); if ( "novalue" != valueType ) kdDebug(35001) << "ERROR: cell " << i << "," << j << " has unknown type '" << valueType << "'." << endl; } } else t.clear(); m_currentData.setCell(i,j, t ); /* if ( e.hasAttribute( "hide" ) ) { tmpMissing[cols*j+i] = (bool)e.attribute("hide").toInt( &ok ); if ( !ok ) return false; } else { tmpMissing[cols*j+i] = false; } if ( e.hasAttribute( "dist" ) ) { tmpExp[cols*j+i] = e.attribute("dist").toInt( &ok ); if ( !ok ) return false; } else { tmpExp[cols*j+i] = 0; } */ n = n.nextSibling(); } } } /* m_params->missing=tmpMissing; m_params->explode=tmpExp; */ return true; } // ---------------------------------------------------------------- // Save and Load real old KChart file format bool KChartPart::loadOldXML( const TQDomDocument& doc ) { kdDebug(35001) << "kchart loadOldXML called" << endl; if ( doc.doctype().name() != "chart" ) return false; kdDebug(35001) << "Ok, it is a chart" << endl; TQDomElement chart = doc.documentElement(); if ( chart.attribute( "mime" ) != "application/x-kchart" && chart.attribute( "mime" ) != "application/vnd.kde.kchart" ) return false; kdDebug(35001) << "Mimetype ok" << endl; #if 0 TQDomElement data = chart.namedItem("data").toElement(); bool ok; int cols = data.attribute("cols").toInt(&ok); kdDebug(35001) << "cols readed as:" << cols << endl; if (!ok) { return false; } int rows = data.attribute("rows").toInt(&ok); if (!ok) { return false; } kdDebug(35001) << rows << " x " << cols << endl; m_currentData.expand(rows, cols); kdDebug(35001) << "Expanded!" << endl; TQDomNode n = data.firstChild(); TQArray tmpExp(rows*cols); TQArray tmpMissing(rows*cols); for (int i=0; i!=rows; i++) { for (int j=0; j!=cols; j++) { if (n.isNull()) { kdDebug(35001) << "Some problems, there is less data than it should be!" << endl; break; } TQDomElement e = n.toElement(); if ( !e.isNull() && e.tagName() == "cell" ) { // add the cell to the corresponding place... double val = e.attribute("value").toDouble(&ok); if (!ok) { return false; } kdDebug(35001) << i << " " << j << "=" << val << endl; KoChart::Value t( val ); // kdDebug(35001) << "Set cell for " << row << "," << col << endl; m_currentData.setCell(i,j,t); if ( e.hasAttribute( "hide" ) ) { tmpMissing[cols*j+i] = (bool)e.attribute("hide").toInt( &ok ); if ( !ok ) return false; } else { tmpMissing[cols*j+i] = false; } if ( e.hasAttribute( "dist" ) ) { tmpExp[cols*j+i] = e.attribute("dist").toInt( &ok ); if ( !ok ) return false; } else { tmpExp[cols*j+i] = 0; } n = n.nextSibling(); } } } m_params->missing=tmpMissing; m_params->explode=tmpExp; #endif /* enum KChartType { KCHARTTYPE_LINE, KCHARTTYPE_AREA, KCHARTTYPE_BAR, KCHARTTYPE_HILOCLOSE, KCHARTTYPE_COMBO_LINE_BAR, aka, VOL[ume] KCHARTTYPE_COMBO_HLC_BAR, KCHARTTYPE_COMBO_LINE_AREA, KCHARTTYPE_COMBO_HLC_AREA, KCHARTTYPE_3DHILOCLOSE, KCHARTTYPE_3DCOMBO_LINE_BAR, KCHARTTYPE_3DCOMBO_LINE_AREA, KCHARTTYPE_3DCOMBO_HLC_BAR, KCHARTTYPE_3DCOMBO_HLC_AREA, KCHARTTYPE_3DBAR, KCHARTTYPE_3DAREA, KCHARTTYPE_3DLINE, KCHARTTYPE_3DPIE, KCHARTTYPE_2DPIE }; */ bool ok; TQDomElement params = chart.namedItem( "params" ).toElement(); if ( params.hasAttribute( "type" ) ) { int type=params.attribute("type").toInt( &ok ); if ( !ok ) return false; switch(type) { case 1: m_params->setChartType(KChartParams::Line); break; case 2: m_params->setChartType(KChartParams::Area); break; case 3: m_params->setChartType(KChartParams::Bar); break; case 4: m_params->setChartType(KChartParams::HiLo); break; case 5: case 6: case 7: case 8: /* KCHARTTYPE_COMBO_LINE_BAR, aka, VOL[ume] KCHARTTYPE_COMBO_HLC_BAR, KCHARTTYPE_COMBO_LINE_AREA, KCHARTTYPE_COMBO_HLC_AREA, */ /* line by default*/ m_params->setChartType(KChartParams::Line); break; case 9: m_params->setChartType(KChartParams::HiLo); break; case 10: m_params->setChartType(KChartParams::Bar); break; case 11: m_params->setChartType(KChartParams::Area); break; case 12: m_params->setChartType(KChartParams::Bar); break; case 13: m_params->setChartType(KChartParams::Area); break; case 14: m_params->setChartType(KChartParams::Bar); break; case 15: m_params->setChartType(KChartParams::Area); break; case 16: m_params->setChartType(KChartParams::Line); break; case 17: case 18: m_params->setChartType(KChartParams::Pie); break; } if ( !ok ) return false; } #if 0 if ( params.hasAttribute( "subtype" ) ) { m_params->stack_type = (KChartStackType)params.attribute("subtype").toInt( &ok ); if ( !ok ) return false; } if ( params.hasAttribute( "hlc_style" ) ) { m_params->hlc_style = (KChartHLCStyle)params.attribute("hlc_style").toInt( &ok ); if ( !ok ) return false; } if ( params.hasAttribute( "hlc_cap_width" ) ) { m_params->hlc_cap_width = (short)params.attribute( "hlc_cap_width" ).toShort( &ok ); if ( !ok ) return false; } TQDomElement title = params.namedItem( "title" ).toElement(); if ( !title.isNull()) { TQString t = title.text(); m_params->title=t; } TQDomElement titlefont = params.namedItem( "titlefont" ).toElement(); if ( !titlefont.isNull()) { TQDomElement font = titlefont.namedItem( "font" ).toElement(); if ( !font.isNull() ) m_params->setTitleFont(toFont(font)); } TQDomElement xtitle = params.namedItem( "xtitle" ).toElement(); if ( !xtitle.isNull()) { TQString t = xtitle.text(); m_params->xtitle=t; } TQDomElement xtitlefont = params.namedItem( "xtitlefont" ).toElement(); if ( !xtitlefont.isNull()) { TQDomElement font = xtitlefont.namedItem( "font" ).toElement(); if ( !font.isNull() ) m_params->setXTitleFont(toFont(font)); } TQDomElement ytitle = params.namedItem( "ytitle" ).toElement(); if ( !ytitle.isNull()) { TQString t = ytitle.text(); m_params->ytitle=t; } TQDomElement ytitle2 = params.namedItem( "ytitle2" ).toElement(); if ( !ytitle2.isNull()) { TQString t = ytitle2.text(); m_params->ytitle2=t; } TQDomElement ytitlefont = params.namedItem( "ytitlefont" ).toElement(); if ( !ytitlefont.isNull()) { TQDomElement font = ytitlefont.namedItem( "font" ).toElement(); if ( !font.isNull() ) m_params->setYTitleFont(toFont(font)); } TQDomElement ylabelfmt = params.namedItem( "ylabelfmt" ).toElement(); if ( !ylabelfmt.isNull()) { TQString t = ylabelfmt.text(); m_params->ylabel_fmt=t; } TQDomElement ylabel2fmt = params.namedItem( "ylabel2fmt" ).toElement(); if ( !ylabel2fmt.isNull()) { TQString t = ylabel2fmt.text(); m_params->ylabel2_fmt=t; } TQDomElement labelfont = params.namedItem( "labelfont" ).toElement(); if ( !labelfont.isNull()) { TQDomElement font = labelfont.namedItem( "font" ).toElement(); if ( !font.isNull() ) m_params->setLabelFont(toFont(font)); } TQDomElement yaxisfont = params.namedItem( "yaxisfont" ).toElement(); if ( !yaxisfont.isNull()) { TQDomElement font = yaxisfont.namedItem( "font" ).toElement(); if ( !font.isNull() ) m_params->setYAxisFont(toFont(font)); } TQDomElement xaxisfont = params.namedItem( "xaxisfont" ).toElement(); if ( !xaxisfont.isNull()) { TQDomElement font = xaxisfont.namedItem( "font" ).toElement(); if ( !font.isNull() ) m_params->setXAxisFont(toFont(font)); } TQDomElement annotationFont = params.namedItem("annotationfont").toElement(); if ( !annotationFont.isNull()) { TQDomElement font = annotationFont.namedItem( "font" ).toElement(); if ( !font.isNull() ) m_params->setAnnotationFont(toFont(font)); } TQDomElement yaxis = params.namedItem( "yaxis" ).toElement(); if ( !yaxis.isNull()) { if (yaxis.hasAttribute( "yinterval" )) { m_params->requested_yinterval= yaxis.attribute("yinterval").toDouble( &ok ); if ( !ok ) return false; } if (yaxis.hasAttribute( "ymin" )) { m_params->requested_ymin= yaxis.attribute("ymin").toDouble( &ok ); if ( !ok ) return false; } if (yaxis.hasAttribute( "ymax" ) ) { m_params->requested_ymax= yaxis.attribute("ymax").toDouble( &ok ); if ( !ok ) return false; } } #endif TQDomElement graph = params.namedItem( "graph" ).toElement(); if (!graph.isNull()) { if (graph.hasAttribute( "grid" )) { bool b=(bool) graph.attribute("grid").toInt( &ok ); m_params->setAxisShowGrid(KDChartAxisParams::AxisPosLeft,b ); m_params->setAxisShowGrid(KDChartAxisParams::AxisPosBottom,b ); if (!ok) return false; } if (graph.hasAttribute( "xaxis" )) { bool b=(bool) graph.attribute("xaxis").toInt( &ok ); if (!ok) return false; m_params->setAxisVisible(KDChartAxisParams::AxisPosBottom,b); } if (graph.hasAttribute( "yaxis" )) { bool b=(bool) graph.attribute("yaxis").toInt( &ok ); if (!ok) return false; m_params->setAxisVisible(KDChartAxisParams::AxisPosLeft,b); } #if 0 //no implemented if (graph.hasAttribute( "shelf" )) { m_params->shelf=(bool) graph.attribute("shelf").toInt( &ok ); if (!ok) return false; } #endif if (graph.hasAttribute( "yaxis2" )) { bool b=(bool) graph.attribute("yaxis2").toInt( &ok ); if (!ok) return false; m_params->setAxisVisible(KDChartAxisParams::AxisPosRight,b); } #if 0 //no implemented if (graph.hasAttribute( "ystyle" )) { m_params->yval_style=(bool) graph.attribute("ystyle").toInt( &ok ); if (!ok) return false; } if (graph.hasAttribute( "border" )) { m_params->border=(bool) graph.attribute("border").toInt( &ok ); if (!ok) return false; } if (graph.hasAttribute( "transbg" )) { m_params->transparent_bg=(bool) graph.attribute("transbg").toInt( &ok ); if (!ok) return false; } if (graph.hasAttribute( "xlabel" )) { m_params->hasxlabel=(bool) graph.attribute("xlabel").toInt( &ok ); if (!ok) return false; } if ( graph.hasAttribute( "xlabel_spacing" ) ) { m_params->xlabel_spacing = (short)graph.attribute( "xlabel_spacing" ).toShort( &ok ); if ( !ok ) return false; } if ( graph.hasAttribute( "ylabel_density" ) ) { m_params->ylabel_density = (short)graph.attribute( "ylabel_density" ).toShort( &ok ); if ( !ok ) return false; } if (graph.hasAttribute( "line")) { m_params->label_line=(bool) graph.attribute("line").toInt( &ok ); if (!ok) return false; } if (graph.hasAttribute( "percent")) { m_params->percent_labels=(KChartPercentType) graph.attribute("percent").toInt( &ok ); if (!ok) return false; } if (graph.hasAttribute("cross")) { m_params->cross=(bool) graph.attribute("cross").toInt( &ok ); if (!ok) return false; } if (graph.hasAttribute("thumbnail")) { m_params->thumbnail=(bool) graph.attribute("thumbnail").toInt( &ok ); if (!ok) return false; } if (graph.hasAttribute("thumblabel")) { m_params->thumblabel= graph.attribute("thumblabel"); } if (graph.hasAttribute("thumbval")) { m_params->thumbval=(bool) graph.attribute("thumbval").toDouble( &ok ); if (!ok) return false; } #endif } #if 0 TQDomElement graphparams = params.namedItem( "graphparams" ).toElement(); if (!graphparams.isNull()) { if (graphparams.hasAttribute( "dept3d" )) { m_params->_3d_depth=graphparams.attribute("dept3d").toDouble( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "angle3d" )) { m_params->_3d_angle=graphparams.attribute("angle3d").toShort( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "barwidth" )) { m_params->bar_width=graphparams.attribute("barwidth").toShort( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "colpie" )) { m_params->colPie=graphparams.attribute("colpie").toInt( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "other_threshold" )) { m_params->other_threshold=graphparams.attribute("other_threshold").toShort( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "offsetCol" )) { m_params->offsetCol = graphparams.attribute("offsetCol").toInt( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "hard_size" )) { m_params->hard_size = (bool)graphparams.attribute("hard_size").toInt( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "hard_graphheight" )) { m_params->hard_graphheight = graphparams.attribute("hard_graphheight").toInt( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "hard_graphwidth" )) { m_params->hard_graphwidth = graphparams.attribute("hard_graphwidth").toInt( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "hard_xorig" )) { m_params->hard_xorig = graphparams.attribute("hard_xorig").toInt( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "hard_yorig" )) { m_params->hard_yorig = graphparams.attribute("hard_yorig").toInt( &ok ); if (!ok) return false; } if (graphparams.hasAttribute( "labeldist" )) { m_params->label_dist=graphparams.attribute("labeldist").toInt( &ok ); if (!ok) return false; } } TQDomElement graphcolor = params.namedItem( "graphcolor" ).toElement(); if (!graphcolor.isNull()) { if (graphcolor.hasAttribute( "bgcolor" )) { m_params->BGColor= TQColor( graphcolor.attribute( "bgcolor" ) ); } if (graphcolor.hasAttribute( "gridcolor" )) { m_params->GridColor= TQColor( graphcolor.attribute( "gridcolor" ) ); } if (graphcolor.hasAttribute( "linecolor" )) { m_params->LineColor= TQColor( graphcolor.attribute( "linecolor" ) ); } if (graphcolor.hasAttribute( "plotcolor" )) { m_params->PlotColor= TQColor( graphcolor.attribute( "plotcolor" ) ); } if (graphcolor.hasAttribute( "volcolor" )) { m_params->VolColor= TQColor( graphcolor.attribute( "volcolor" ) ); } if (graphcolor.hasAttribute( "titlecolor" )) { m_params->TitleColor= TQColor( graphcolor.attribute( "titlecolor" ) ); } if (graphcolor.hasAttribute( "xtitlecolor" )) { m_params->XTitleColor= TQColor( graphcolor.attribute( "xtitlecolor" ) ); } if (graphcolor.hasAttribute( "ytitlecolor" )) { m_params->YTitleColor= TQColor( graphcolor.attribute( "ytitlecolor" ) ); } if (graphcolor.hasAttribute( "ytitle2color" )) { m_params->YTitle2Color= TQColor( graphcolor.attribute( "ytitle2color" ) ); } if (graphcolor.hasAttribute( "xlabelcolor" )) { m_params->XLabelColor= TQColor( graphcolor.attribute( "xlabelcolor" ) ); } if (graphcolor.hasAttribute( "ylabelcolor" )) { m_params->YLabelColor= TQColor( graphcolor.attribute( "ylabelcolor" ) ); } if (graphcolor.hasAttribute( "ylabel2color" )) { m_params->YLabel2Color= TQColor( graphcolor.attribute( "ylabel2color" ) ); } } TQDomElement annotation = params.namedItem( "annotation" ).toElement(); if (!annotation.isNull()) { m_params->annotation=new KChartAnnotationType; if (annotation.hasAttribute( "color" )) { m_params->annotation->color= TQColor( annotation.attribute( "color" ) ); } if (annotation.hasAttribute( "point" )) { m_params->annotation->point=annotation.attribute("point").toDouble( &ok ); if (!ok) return false; } } TQDomElement note = params.namedItem( "note" ).toElement(); if ( !note.isNull()) { TQString t = note.text(); m_params->annotation->note=t; } TQDomElement scatter = params.namedItem( "scatter" ).toElement(); if ( !scatter.isNull() ) { m_params->scatter = new KChartScatterType; if ( scatter.hasAttribute( "point" ) ) { m_params->scatter->point = scatter.attribute( "point" ).toDouble( &ok ); if ( !ok ) return false; } if ( scatter.hasAttribute( "val" ) ) { m_params->scatter->val = scatter.attribute( "val" ).toDouble( &ok ); if ( !ok ) return false; } if ( scatter.hasAttribute( "width" ) ) { m_params->scatter->width = scatter.attribute( "val" ).toUShort( &ok ); if ( !ok ) return false; } if ( scatter.hasAttribute( "color" )) { m_params->scatter->color= TQColor( scatter.attribute( "color" ) ); } if ( scatter.hasAttribute( "ind" ) ) { m_params->scatter->ind = (KChartScatterIndType)scatter.attribute( "ind" ).toInt( &ok ); if ( !ok ) return false; } } TQDomElement legend = chart.namedItem("legend").toElement(); if (!legend.isNull()) { int number = legend.attribute("number").toInt(&ok); if (!ok) { return false; } TQDomNode name = legend.firstChild(); m_params->legend.clear(); for(int i=0; ilegend+=t; name = name.nextSibling(); } } } TQDomElement xlbl = chart.namedItem("xlbl").toElement(); if (!xlbl.isNull()) { int number = xlbl.attribute("number").toInt(&ok); if (!ok) { return false; } TQDomNode label = xlbl.firstChild(); m_params->xlbl.clear(); for (int i=0; ixlbl+=t; label = label.nextSibling(); } } } TQDomElement backgroundPixmap = chart.namedItem( "backgroundPixmap" ).toElement(); if ( !backgroundPixmap.isNull() ) { if ( backgroundPixmap.hasAttribute( "name" ) ) m_params->backgroundPixmapName = backgroundPixmap.attribute( "name" ); if ( backgroundPixmap.hasAttribute( "isDirty" ) ) { m_params->backgroundPixmapIsDirty = (bool)backgroundPixmap.attribute( "isDirty" ).toInt( &ok ); if ( !ok ) return false; } if ( backgroundPixmap.hasAttribute( "scaled" ) ) { m_params->backgroundPixmapScaled = (bool)backgroundPixmap.attribute( "scaled" ).toInt( &ok ); if ( !ok ) return false; } if ( backgroundPixmap.hasAttribute( "centered" ) ) { m_params->backgroundPixmapCentered = (bool)backgroundPixmap.attribute( "centered" ).toInt( &ok ); if ( !ok ) return false; } if ( backgroundPixmap.hasAttribute( "intensity" ) ) { m_params->backgroundPixmapIntensity = backgroundPixmap.attribute( "intensity" ).toFloat( &ok ); if ( !ok ) return false; } } TQDomElement extcolor = chart.namedItem("extcolor").toElement(); if (!extcolor.isNull()) { unsigned int number = extcolor.attribute("number").toInt(&ok); if (!ok) { return false; } TQDomNode color = extcolor.firstChild(); for (unsigned int i=0; iExtColor.setColor(i,TQColor( element.attribute( "name" ) )); } color = color.nextSibling(); } } } if ( !m_params->backgroundPixmapName.isNull() ) { m_params->backgroundPixmap.load( locate( "wallpaper", m_params->backgroundPixmapName )); m_params->backgroundPixmapIsDirty = true; } #endif return true; } void KChartPart::slotModified() { kdDebug(35001) << "slotModified called!" << endl; setModified(true); } bool KChartPart::showEmbedInitDialog(TQWidget* /*tqparent*/) { // Don't show an embed dialog return true; } } //KChart namespace #include "kchart_part.moc"