File indexing completed on 2024-05-12 15:53:54

0001 /**
0002  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
0003  *
0004  * This file is part of the KD Chart library.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "mainwindow.h"
0021 #include "framewidget.h"
0022 
0023 #include <KChartChart>
0024 #include <KChartAbstractCoordinatePlane>
0025 #include <KChartLineDiagram>
0026 #include <KChartLineAttributes>
0027 #include <KChartTextAttributes>
0028 #include <KChartDataValueAttributes>
0029 #include <KChartThreeDLineAttributes>
0030 #include <KChartMarkerAttributes>
0031 #include <KChartFrameAttributes>
0032 #include <KChartBackgroundAttributes>
0033 #include <KChartLegend>
0034 
0035 #include <QDebug>
0036 #include <QPainter>
0037 #include <QTime>
0038 #include <QElapsedTimer>
0039 
0040 using namespace KChart;
0041 
0042 static QPixmap drawIntoPixmap( const QSize& size, KChart::Chart* chart )
0043 {
0044     QPixmap pix( size );
0045     pix.fill( Qt::white );
0046     QPainter painter( &pix );
0047     chart->paint( &painter, QRect( 0, 0, size.width(), size.height() ) );
0048     return pix;
0049 }
0050 
0051 // When set, this example uses FrameWidget which uses Chart::paint to paint itself.
0052 // When not set, this example uses a Chart widget directly.
0053 #define USE_FRAME_WIDGET 1
0054 
0055 
0056 MainWindow::MainWindow( QWidget* parent ) :
0057     QWidget( parent )
0058 {
0059 
0060     setupUi( this );
0061 
0062     connect( lineTypeCB, SIGNAL(currentIndexChanged(QString)), this, SLOT(setLineType(QString)) );
0063     connect( paintLegendCB, SIGNAL(toggled(bool)), this, SLOT(setLegendVisible(bool)) );
0064     connect( paintValuesCB, SIGNAL(toggled(bool)), this, SLOT(setValuesVisible(bool)) );
0065     connect( paintMarkersCB, SIGNAL(toggled(bool)), this, SLOT(setMarkersVisible(bool)) );
0066     connect( markersStyleCB, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMarkers()) );
0067     connect( markersWidthSB, SIGNAL(valueChanged(int)), this, SLOT(updateMarkersHeight()) );
0068     connect( markersHeightSB, SIGNAL(valueChanged(int)), this, SLOT(updateMarkersWidth()) );
0069     connect( displayAreasCB, SIGNAL(toggled(bool)), this, SLOT(updateAreas(bool)) );
0070     connect( transparencySB, SIGNAL(valueChanged(int)), this, SLOT(updateAreasTransparency()) );
0071     connect( zoomFactorSB, SIGNAL(valueChanged(double)), this, SLOT(setZoomFactor(qreal)) );
0072     connect( hSBar, SIGNAL(valueChanged(int)), this, SLOT(setHPos(int)) );
0073     connect( vSBar, SIGNAL(valueChanged(int)), this, SLOT(setVPos(int)) );
0074     connect( savePB, SIGNAL(clicked()), this, SLOT(saveChart()) );
0075 
0076     QHBoxLayout* chartLayout = new QHBoxLayout( chartFrame );
0077 #ifdef USE_FRAME_WIDGET
0078     FrameWidget* chartFrameWidget = new FrameWidget();
0079     chartLayout->addWidget( chartFrameWidget );
0080 #endif
0081     hSBar->setVisible( false );
0082     vSBar->setVisible( false );
0083 
0084     m_model.loadFromCSV( ":/empty" );
0085 
0086     // Set up the diagram
0087     m_lines = new LineDiagram();
0088 
0089     m_lines->setModel( &m_model );
0090 
0091     CartesianAxis *xAxis = new CartesianAxis( m_lines );
0092     CartesianAxis *yAxis = new CartesianAxis ( m_lines );
0093     CartesianAxis *axisTop = new CartesianAxis ( m_lines );
0094     CartesianAxis *axisRight = new CartesianAxis ( m_lines );
0095     xAxis->setPosition ( KChart::CartesianAxis::Bottom );
0096     yAxis->setPosition ( KChart::CartesianAxis::Left );
0097     axisTop->setPosition( KChart::CartesianAxis::Top );
0098     axisRight->setPosition( KChart::CartesianAxis::Right );
0099 
0100     m_lines->addAxis( xAxis );
0101     m_lines->addAxis( yAxis );
0102     m_lines->addAxis( axisTop );
0103     m_lines->addAxis( axisRight );
0104 
0105     m_chart = new Chart();
0106     //m_chart->setGlobalLeading(10,10,10,10); // by default there is no leading
0107 
0108 #ifdef USE_FRAME_WIDGET
0109     chartFrameWidget->setChart( m_chart );
0110     // make sure, we re-draw after changing one of the chart's properties
0111     connect( m_chart,          SIGNAL(propertiesChanged()),
0112              chartFrameWidget, SLOT(update()) ) ;
0113 #else
0114     chartLayout->addWidget( m_chart );
0115 #endif
0116 
0117     m_chart->coordinatePlane()->replaceDiagram( m_lines );
0118 
0119     for ( int iColumn = 0; iColumn<m_lines->model()->columnCount(); ++iColumn ) {
0120         QPen pen(m_lines->pen( iColumn ));
0121         pen.setWidth(4);
0122         m_lines->setPen( iColumn, pen );
0123     }
0124 
0125     FrameAttributes faChart( m_chart->frameAttributes() );
0126     faChart.setVisible( true );
0127     faChart.setPen( QPen(QColor(0x60,0x60,0xb0), 8) );
0128     m_chart->setFrameAttributes( faChart );
0129 
0130     BackgroundAttributes baChart( m_chart->backgroundAttributes() );
0131     baChart.setVisible( true );
0132     baChart.setBrush( QColor(0xd0,0xd0,0xff) );
0133     m_chart->setBackgroundAttributes( baChart );
0134 
0135     // Set up the legend
0136     m_legend = new Legend( m_lines, m_chart );
0137 
0138     m_legend->setPosition( Position::South );
0139     m_legend->setAlignment( Qt::AlignRight );
0140     m_legend->setShowLines( false );
0141     m_legend->setTitleText( QStringLiteral( "Legend" ) );
0142     m_legend->setOrientation( Qt::Horizontal );
0143 
0144     // setting the legend frame and background to the same color:
0145     const QColor legendColor(0xff,0xe0,0x80);
0146     FrameAttributes faLegend( m_legend->frameAttributes() );
0147     faLegend.setVisible( true );
0148     faLegend.setPen( QPen(legendColor, 1) );
0149     m_legend->setFrameAttributes( faLegend );
0150 
0151     BackgroundAttributes baLegend( m_legend->backgroundAttributes() );
0152     baLegend.setVisible( true );
0153     baLegend.setBrush( legendColor );
0154     m_legend->setBackgroundAttributes( baLegend );
0155 
0156     m_chart->addLegend( m_legend );
0157 
0158     // for illustration we paint the same chart at different sizes:
0159     QSize size1 = QSize( 200, 200 );
0160     QSize size2 = QSize( 800, 800 );
0161     m_pix1 = drawIntoPixmap( size1, m_chart );
0162     m_pix2 = drawIntoPixmap( size2, m_chart );
0163     m_pix2 = m_pix2.scaled( size1 );
0164 
0165     m_smallChart1 = new QLabel( this );
0166     m_smallChart1->setWindowTitle( "200x200" );
0167     m_smallChart1->setPixmap( m_pix1 );
0168     m_smallChart1->setFixedSize( m_pix1.size() );
0169     m_smallChart1->move( width() - m_pix1.width()*2,
0170                          height()/2 - m_pix1.height()-5 );
0171     m_smallChart1->show();
0172 
0173     m_smallChart2 = new QLabel( this );
0174     m_smallChart2->setWindowTitle( "800x800 scaled down" );
0175     m_smallChart2->setPixmap( m_pix2 );
0176     m_smallChart2->setFixedSize( m_pix2.size() );
0177     m_smallChart2->move( width() - m_pix2.width()*2,
0178                          height()/2 + 5 );
0179     m_smallChart2->show();
0180 
0181     faChart.setPen( QPen(QColor(0xb0,0xb0,0xff), 8) );
0182     m_chart->setFrameAttributes( faChart );
0183 
0184     // initialize attributes; this is necessary because we need to enable data value attributes before
0185     // any of them (e.g. only markers) can be displayed. but if we enable data value attributs, a default
0186     // data value text is included, even if we only wanted to set markers. so we enable DVA and then
0187     // individually disable the parts we don't want.
0188     setValuesVisible( false );
0189     setMarkersVisible( false );
0190 }
0191 
0192 void MainWindow::updateData(QString data)
0193 {
0194     QElapsedTimer t;
0195     t.start();
0196 
0197     m_model.loadFromCSV( data );
0198 
0199     qDebug("Time for loading data %s: %lld ms", data.toLatin1().constData(), t.elapsed());
0200     t.restart();
0201 
0202     QSize size1 = QSize( 200, 200 );
0203     QSize size2 = QSize( 800, 800 );
0204     m_pix1 = drawIntoPixmap( size1, m_chart );
0205     m_pix2 = drawIntoPixmap( size2, m_chart );
0206 
0207     qDebug("Time for drawing pixmap %s: %lld ms", data.toLatin1().constData(), t.elapsed());
0208     t.restart();
0209 
0210     m_lines->setModel( &m_model );
0211 
0212     qDebug("Time for setting model %s: %lld ms", data.toLatin1().constData(), t.elapsed());
0213     t.restart();
0214 
0215     m_smallChart1->setPixmap( m_pix1 );
0216     m_smallChart2->setPixmap( m_pix2 );
0217 
0218     m_smallChart1->show();
0219     m_smallChart2->show();
0220 
0221     qDebug("Time for setting pixmap %s: %lld ms", data.toLatin1().constData(), t.elapsed());
0222     t.restart();
0223 
0224 }
0225 
0226 void MainWindow::setLineType( const QString & text )
0227 {
0228     if ( text == "Normal" )
0229         m_lines->setType( LineDiagram::Normal );
0230     else if ( text == "Stacked" )
0231         m_lines->setType( LineDiagram::Stacked );
0232     else if ( text == "Percent" )
0233         m_lines->setType( LineDiagram::Percent );
0234     else
0235         qWarning (" Does not match any type");
0236 }
0237 
0238 void MainWindow::setLegendVisible(bool visible )
0239 {
0240     KChart::Legend* legend = m_chart->legend();
0241     if ( visible != ( legend != nullptr ) ) {
0242         if ( visible )
0243             m_chart->addLegend( m_legend );
0244         else
0245             m_chart->takeLegend( legend );
0246     }
0247 }
0248 
0249 void MainWindow::setValuesVisible(bool visible )
0250 {
0251     const int colCount = m_lines->model()->columnCount();
0252     for ( int iColumn = 0; iColumn<colCount; ++iColumn ) {
0253         DataValueAttributes a = m_lines->dataValueAttributes( iColumn );
0254         a.setVisible( true );
0255 
0256         TextAttributes ta = a.textAttributes();
0257         ta.setRotation( 0 );
0258         ta.setFont( QFont( "Comic", 10 ) );
0259         ta.setPen( m_lines->brush( iColumn ).color() );
0260         ta.setVisible( visible );
0261 
0262         a.setTextAttributes( ta );
0263         m_lines->setDataValueAttributes( iColumn, a);
0264     }
0265 }
0266 
0267 
0268 void MainWindow::setMarkersVisible( bool visible )
0269 {
0270     paintMarkers( visible, QSize() );
0271 }
0272 
0273 void MainWindow::updateMarkers()
0274 {
0275     setMarkersVisible( paintMarkersCB->isChecked() );
0276 }
0277 
0278 void MainWindow::updateMarkersHeight()
0279 {
0280     markersHeightSB->setValue( markersWidthSB->value() );
0281     updateMarkers();
0282 }
0283 
0284 void MainWindow::updateMarkersWidth()
0285 {
0286     markersWidthSB->setValue( markersHeightSB->value() );
0287     updateMarkers();
0288 }
0289 
0290 void MainWindow::updateAreas( bool visible )
0291 {
0292     const int colCount = m_lines->model()->columnCount();
0293     for ( int iColumn = 0; iColumn<colCount; ++iColumn ) {
0294         LineAttributes la( m_lines->lineAttributes( iColumn ) );
0295         la.setDisplayArea( visible );
0296         if ( visible  )
0297             la.setTransparency( transparencySB->value() );
0298         m_lines->setLineAttributes( iColumn,  la );
0299     }
0300 }
0301 
0302 void MainWindow::updateAreasTransparency()
0303 {
0304     if ( !displayAreasCB->isChecked() )
0305         displayAreasCB->setChecked( true );
0306     else
0307         updateAreas( true );
0308 }
0309 
0310 void MainWindow::setZoomFactor( qreal factor )
0311 {
0312     const bool isZoomedIn = factor > 1.0f;
0313     hSBar->setVisible( isZoomedIn );
0314     vSBar->setVisible( isZoomedIn );
0315     if ( !isZoomedIn ) {
0316         hSBar->setValue( 500 );
0317         vSBar->setValue( 500 );
0318     }
0319     m_chart->coordinatePlane()->setZoomFactorX( factor );
0320     m_chart->coordinatePlane()->setZoomFactorY( factor );
0321 }
0322 
0323 void MainWindow::setHPos( int hPos )
0324 {
0325     m_chart->coordinatePlane()->setZoomCenter( QPointF(hPos/1000.0, vSBar->value()/1000.0) );
0326     m_chart->update();
0327 }
0328 
0329 void MainWindow::setVPos( int vPos )
0330 {
0331     m_chart->coordinatePlane()->setZoomCenter( QPointF( hSBar->value()/1000.0, vPos/1000.0) );
0332 }
0333 
0334 // since DataValue markers have no relative sizing mode we need to scale them for printing
0335 void MainWindow::paintMarkers( bool checked, const QSize& printSize )
0336 {
0337     MarkerAttributes::MarkerStylesMap map;
0338     map.insert( 0, MarkerAttributes::MarkerSquare );
0339     map.insert( 1, MarkerAttributes::MarkerCircle );
0340     map.insert( 2, MarkerAttributes::MarkerRing );
0341     map.insert( 3, MarkerAttributes::MarkerCross );
0342     map.insert( 4, MarkerAttributes::MarkerDiamond );
0343 
0344     // next: Specify column- / cell-specific attributes!
0345     const int colCount = m_lines->model()->columnCount();
0346     for ( int iColumn = 0; iColumn<colCount; ++iColumn ) {
0347         DataValueAttributes dva = m_lines->dataValueAttributes( iColumn );
0348         dva.setVisible( true );
0349         MarkerAttributes ma( dva.markerAttributes() );
0350 
0351     switch ( markersStyleCB->currentIndex() ) {
0352         case 0:
0353                    ma.setMarkerStyle( MarkerAttributes::MarkerSquare );
0354                    break;
0355         case 1:
0356                    // Column-specific attributes
0357                    ma.setMarkerStyle( map.value( iColumn ) );
0358                    break;
0359         case 2:
0360                    ma.setMarkerStyle( MarkerAttributes::MarkerCircle );
0361                    break;
0362         case 3:
0363                    ma.setMarkerStyle( MarkerAttributes::MarkerDiamond );
0364                    break;
0365         case 4:
0366                    ma.setMarkerStyle( MarkerAttributes::Marker1Pixel );
0367                    break;
0368         case 5:
0369                    ma.setMarkerStyle( MarkerAttributes::Marker4Pixels );
0370                    break;
0371         case 6:
0372                    ma.setMarkerStyle( MarkerAttributes::MarkerRing );
0373                    break;
0374         case 7:
0375                    ma.setMarkerStyle( MarkerAttributes::MarkerCross );
0376                    break;
0377         case 8:
0378                    ma.setMarkerStyle( MarkerAttributes::MarkerFastCross );
0379                    break;
0380         default:
0381             Q_ASSERT( false );
0382     }
0383     ma.setVisible( checked );
0384 
0385         qreal factorWidth = printSize.isValid() ? ( printSize.width() / m_chart->rect().width() ) : 1.0f;
0386         qreal factorHeight = printSize.isValid() ? ( printSize.height() / m_chart->rect().height() ) : 1.0f;
0387         ma.setMarkerSize( QSize( markersWidthSB->value() * factorWidth, markersHeightSB->value() * factorHeight ) );
0388 
0389         dva.setMarkerAttributes( ma );
0390         m_lines->setDataValueAttributes( iColumn, dva );
0391 
0392     // make a special one for certain values
0393     DataValueAttributes yellowAttributes( dva );
0394     MarkerAttributes yellowMarker( yellowAttributes.markerAttributes() );
0395     yellowMarker.setMarkerColor( Qt::yellow );
0396     yellowAttributes.setMarkerAttributes( yellowMarker );
0397 
0398     const int rowCount = m_lines->model()->rowCount();
0399         for ( int j=0; j< rowCount; ++j ) {
0400             QModelIndex index = m_lines->model()->index( j, iColumn, QModelIndex() );
0401             QBrush brush = m_lines->model()->headerData( iColumn, Qt::Vertical, DatasetBrushRole ).value<QBrush>();
0402             qreal value = m_lines->model()->data( index ).toReal();
0403             /* Set a specific color - marker for a specific value */
0404             if ( value == 13 ) {
0405                 m_lines->setDataValueAttributes( index, yellowAttributes );
0406             }
0407         }
0408     }
0409 }
0410 
0411 void MainWindow::saveChart()
0412 {
0413     qDebug() << "Painting into PNG";
0414     QPixmap qpix(600,600);
0415     QPainter painter(&qpix);
0416     painter.setBrush(Qt::white);
0417     painter.fillRect( 0, 0, 600, 600, Qt::white);
0418     m_chart->paint( &painter,
0419                     QRect(100, 100, 400, 400) );
0420     painter.end();
0421     qpix.save("kchart-demo.png", "PNG");
0422     qDebug() << "Painting into PNG - done";
0423 }
0424 
0425 void MainWindow::resizeEvent ( QResizeEvent * )
0426 {
0427     m_smallChart1->move( width() - m_pix1.width()*2,
0428                          height()/2 - m_pix1.height()-5 );
0429     m_smallChart2->move( width() - m_pix2.width()*2,
0430                          height()/2 + 5 );
0431 }
0432 
0433