File indexing completed on 2024-05-19 15:26:53

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 <QFileDialog>
0038 #include <QPrinter>
0039 #include <QPrintPreviewDialog>
0040 
0041 using namespace KChart;
0042 
0043 static QPixmap drawIntoPixmap( const QSize& size, KChart::Chart* chart )
0044 {
0045     QPixmap pix( size );
0046     pix.fill( Qt::white );
0047     QPainter painter( &pix );
0048     chart->paint( &painter, QRect( 0, 0, size.width(), size.height() ) );
0049     return pix;
0050 }
0051 
0052 // When set, this example uses FrameWidget which uses Chart::paint to paint itself.
0053 // When not set, this example uses a Chart widget directly.
0054 #define USE_FRAME_WIDGET 1
0055 
0056 
0057 MainWindow::MainWindow( QWidget* parent ) :
0058     QWidget( parent )
0059 {
0060     setupUi( this );
0061 
0062     QHBoxLayout* chartLayout = new QHBoxLayout( chartFrame );
0063 #ifdef USE_FRAME_WIDGET
0064     FrameWidget* chartFrameWidget = new FrameWidget();
0065     chartLayout->addWidget( chartFrameWidget );
0066 #endif
0067     hSBar->setVisible( false );
0068     vSBar->setVisible( false );
0069 
0070     m_model.loadFromCSV( ":/data" );
0071 
0072     // Set up the diagram
0073     m_lines = new LineDiagram();
0074     m_lines->setModel( &m_model );
0075 
0076     CartesianAxis *xAxis = new CartesianAxis( m_lines );
0077     CartesianAxis *yAxis = new CartesianAxis( m_lines );
0078     CartesianAxis *axisTop = new CartesianAxis( m_lines );
0079     CartesianAxis *axisRight = new CartesianAxis( m_lines );
0080     xAxis->setPosition( KChart::CartesianAxis::Bottom );
0081     yAxis->setPosition( KChart::CartesianAxis::Left );
0082     axisTop->setPosition( KChart::CartesianAxis::Top );
0083     axisRight->setPosition( KChart::CartesianAxis::Right );
0084 
0085     m_lines->addAxis( xAxis );
0086     m_lines->addAxis( yAxis );
0087     m_lines->addAxis( axisTop );
0088     m_lines->addAxis( axisRight );
0089 
0090     m_chart = new Chart();
0091     //m_chart->setGlobalLeading(10,10,10,10); // by default there is no leading
0092 
0093 #ifdef USE_FRAME_WIDGET
0094     chartFrameWidget->setChart( m_chart );
0095     // make sure, we re-draw after changing one of the chart's properties
0096     connect( m_chart,          SIGNAL(propertiesChanged()),
0097              chartFrameWidget, SLOT(update()) ) ;
0098 #else
0099     chartLayout->addWidget( m_chart );
0100 #endif
0101 
0102     m_chart->coordinatePlane()->replaceDiagram( m_lines );
0103 
0104     for ( int iColumn = 0; iColumn < m_lines->model()->columnCount(); ++iColumn ) {
0105         QPen pen(m_lines->pen( iColumn ));
0106         pen.setWidth(4);
0107         m_lines->setPen( iColumn, pen );
0108     }
0109 
0110     FrameAttributes faChart( m_chart->frameAttributes() );
0111     faChart.setVisible( true );
0112     faChart.setPen( QPen(QColor( 0x60, 0x60, 0xb0 ), 8 ) );
0113     m_chart->setFrameAttributes( faChart );
0114 
0115     BackgroundAttributes baChart( m_chart->backgroundAttributes() );
0116     baChart.setVisible( true );
0117     baChart.setBrush( QColor( 0xd0, 0xd0, 0xff ) );
0118     m_chart->setBackgroundAttributes( baChart );
0119 
0120     // Set up the legend
0121     m_legend = new Legend( m_lines, m_chart );
0122 
0123     m_legend->setPosition( Position::South );
0124     m_legend->setAlignment( Qt::AlignRight );
0125     m_legend->setShowLines( false );
0126     m_legend->setTitleText( tr( "Legend" ) );
0127     m_legend->setOrientation( Qt::Horizontal );
0128 
0129     // setting the legend frame and background to the same color:
0130     const QColor legendColor( 0xff, 0xe0, 0x80 );
0131     FrameAttributes faLegend( m_legend->frameAttributes() );
0132     faLegend.setVisible( true );
0133     faLegend.setPen( QPen( legendColor, 1 ) );
0134     m_legend->setFrameAttributes( faLegend );
0135 
0136     BackgroundAttributes baLegend( m_legend->backgroundAttributes() );
0137     baLegend.setVisible( true );
0138     baLegend.setBrush( legendColor );
0139     m_legend->setBackgroundAttributes( baLegend );
0140 
0141     m_chart->addLegend( m_legend );
0142 
0143     // for illustration we paint the same chart at different sizes:
0144     QSize size1 = QSize( 200, 200 );
0145     QSize size2 = QSize( 800, 800 );
0146     m_pix1 = drawIntoPixmap( size1, m_chart );
0147     m_pix2 = drawIntoPixmap( size2, m_chart );
0148     m_pix2 = m_pix2.scaled( size1 );
0149 
0150     m_smallChart1 = new QLabel( this );
0151     m_smallChart1->setWindowTitle( "200x200" );
0152     m_smallChart1->setPixmap( m_pix1 );
0153     m_smallChart1->setFixedSize( m_pix1.size() );
0154     m_smallChart1->move( width() - m_pix1.width() * 2,
0155                          height() / 2 - m_pix1.height() - 5 );
0156     m_smallChart1->show();
0157 
0158     m_smallChart2 = new QLabel( this );
0159     m_smallChart2->setWindowTitle( "800x800 scaled down" );
0160     m_smallChart2->setPixmap( m_pix2 );
0161     m_smallChart2->setFixedSize( m_pix2.size() );
0162     m_smallChart2->move( width() - m_pix2.width() * 2,
0163                          height() / 2 + 5 );
0164     m_smallChart2->show();
0165 
0166     faChart.setPen( QPen( QColor( 0xb0, 0xb0, 0xff ), 8 ) );
0167     m_chart->setFrameAttributes( faChart );
0168 
0169     // initialize attributes; this is necessary because we need to enable data value attributes before
0170     // any of them (e.g. only markers) can be displayed. but if we enable data value attributs, a default
0171     // data value text is included, even if we only wanted to set markers. so we enable DVA and then
0172     // individually disable the parts we don't want.
0173     on_paintValuesCB_toggled( false );
0174     on_paintMarkersCB_toggled( false );
0175 }
0176 
0177 void MainWindow::slotPaintRequested(QPrinter *printer)
0178 {
0179     QPainter painter(printer);
0180     m_chart->paint(&painter, painter.window());
0181 }
0182 
0183 void MainWindow::on_printButton_clicked()
0184 {
0185     static QPrinter printer;
0186     QPrintPreviewDialog dialog(&printer);
0187     connect(&dialog, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPaintRequested(QPrinter*)));
0188     dialog.exec();
0189 }
0190 
0191 void MainWindow::on_lineTypeCB_currentIndexChanged( const QString & text )
0192 {
0193     if ( text == "Normal" )
0194         m_lines->setType( LineDiagram::Normal );
0195     else if ( text == "Stacked" )
0196         m_lines->setType( LineDiagram::Stacked );
0197     else if ( text == "Percent" )
0198         m_lines->setType( LineDiagram::Percent );
0199     else
0200         qWarning (" Does not match any type");
0201 }
0202 
0203 
0204 void MainWindow::on_paintLegendCB_toggled( bool checked )
0205 {
0206     KChart::Legend* legend = m_chart->legend();
0207     if ( checked != ( legend != nullptr ) ) {
0208         if ( checked )
0209             m_chart->addLegend( m_legend );
0210         else
0211             m_chart->takeLegend( legend );
0212     }
0213 }
0214 
0215 void MainWindow::on_paintValuesCB_toggled( bool checked )
0216 {
0217     const int colCount = m_lines->model()->columnCount();
0218     for ( int iColumn = 0; iColumn < colCount; ++iColumn ) {
0219         DataValueAttributes a = m_lines->dataValueAttributes( iColumn );
0220         a.setVisible( true );
0221 
0222         TextAttributes ta = a.textAttributes();
0223         ta.setRotation( 0 );
0224         ta.setFont( QFont( "Comic", 10 ) );
0225         ta.setPen( m_lines->brush( iColumn ).color() );
0226         ta.setVisible( checked );
0227 
0228         a.setTextAttributes( ta );
0229         m_lines->setDataValueAttributes( iColumn, a );
0230     }
0231 }
0232 
0233 
0234 void MainWindow::on_paintMarkersCB_toggled( bool checked )
0235 {
0236     paintMarkers( checked, QSize() );
0237 }
0238 
0239 void MainWindow::on_markersStyleCB_currentIndexChanged( const QString & text )
0240 {
0241     Q_UNUSED( text );
0242     on_paintMarkersCB_toggled( paintMarkersCB->isChecked() );
0243 }
0244 
0245 
0246 void MainWindow::on_markersWidthSB_valueChanged( int i )
0247 {
0248     Q_UNUSED( i );
0249     markersHeightSB->setValue( markersWidthSB->value() );
0250     on_paintMarkersCB_toggled( paintMarkersCB->isChecked() );
0251 }
0252 
0253 void MainWindow::on_markersHeightSB_valueChanged( int i )
0254 {
0255     Q_UNUSED( i );
0256     markersWidthSB->setValue( markersHeightSB->value() );
0257     on_paintMarkersCB_toggled( paintMarkersCB->isChecked() );
0258 }
0259 
0260 
0261 void MainWindow::on_displayAreasCB_toggled( bool checked )
0262 {
0263     const int colCount = m_lines->model()->columnCount();
0264     for ( int iColumn = 0; iColumn < colCount; ++iColumn ) {
0265         LineAttributes la( m_lines->lineAttributes( iColumn ) );
0266         la.setDisplayArea( checked );
0267         if ( checked  )
0268             la.setTransparency( transparencySB->value() );
0269         m_lines->setLineAttributes( iColumn,  la );
0270     }
0271 }
0272 
0273 void MainWindow::on_transparencySB_valueChanged( int alpha )
0274 {
0275     Q_UNUSED( alpha );
0276     if ( !displayAreasCB->isChecked() )
0277         displayAreasCB->setChecked( true );
0278     else
0279         on_displayAreasCB_toggled( true );
0280 }
0281 
0282 void MainWindow::on_zoomFactorSB_valueChanged( qreal factor )
0283 {
0284     const bool isZoomedIn = factor > 1.0f;
0285     hSBar->setVisible( isZoomedIn );
0286     vSBar->setVisible( isZoomedIn );
0287     if ( !isZoomedIn ) {
0288         hSBar->setValue( 500 );
0289         vSBar->setValue( 500 );
0290     }
0291     m_chart->coordinatePlane()->setZoomFactorX( factor );
0292     m_chart->coordinatePlane()->setZoomFactorY( factor );
0293 }
0294 
0295 void MainWindow::on_hSBar_valueChanged( int hPos )
0296 {
0297     m_chart->coordinatePlane()->setZoomCenter( QPointF( hPos / 1000.0, vSBar->value() / 1000.0 ) );
0298     m_chart->update();
0299 }
0300 
0301 void MainWindow::on_vSBar_valueChanged( int vPos )
0302 {
0303     m_chart->coordinatePlane()->setZoomCenter( QPointF( hSBar->value() / 1000.0, vPos / 1000.0 ) );
0304 }
0305 
0306 // since DataValue markers have no relative sizing mode we need to scale them for printing
0307 void MainWindow::paintMarkers( bool checked, const QSize& printSize )
0308 {
0309     MarkerAttributes::MarkerStylesMap map;
0310     map.insert( 0, MarkerAttributes::MarkerSquare );
0311     map.insert( 1, MarkerAttributes::MarkerCircle );
0312     map.insert( 2, MarkerAttributes::MarkerRing );
0313     map.insert( 3, MarkerAttributes::MarkerCross );
0314     map.insert( 4, MarkerAttributes::MarkerDiamond );
0315 
0316     // next: Specify column- / cell-specific attributes!
0317     const int colCount = m_lines->model()->columnCount();
0318     for ( int iColumn = 0; iColumn < colCount; ++iColumn ) {
0319 
0320         DataValueAttributes dva = m_lines->dataValueAttributes( iColumn );
0321         dva.setVisible( true );
0322         MarkerAttributes ma( dva.markerAttributes() );
0323 
0324         switch ( markersStyleCB->currentIndex() ) {
0325         case 0:
0326             ma.setMarkerStyle( MarkerAttributes::MarkerSquare );
0327             break;
0328         case 1:
0329             // Column-specific attributes
0330             ma.setMarkerStyle( map.value( iColumn ) );
0331             break;
0332         case 2:
0333             ma.setMarkerStyle( MarkerAttributes::MarkerCircle );
0334             break;
0335         case 3:
0336             ma.setMarkerStyle( MarkerAttributes::MarkerDiamond );
0337             break;
0338         case 4:
0339             ma.setMarkerStyle( MarkerAttributes::Marker1Pixel );
0340             break;
0341         case 5:
0342             ma.setMarkerStyle( MarkerAttributes::Marker4Pixels );
0343             break;
0344         case 6:
0345             ma.setMarkerStyle( MarkerAttributes::MarkerRing );
0346             break;
0347         case 7:
0348             ma.setMarkerStyle( MarkerAttributes::MarkerCross );
0349             break;
0350         case 8:
0351             ma.setMarkerStyle( MarkerAttributes::MarkerFastCross );
0352             break;
0353         default:
0354             Q_ASSERT( false );
0355         }
0356         ma.setVisible( checked );
0357 
0358         qreal factorWidth = printSize.isValid() ? ( printSize.width() / m_chart->rect().width() ) : 1.0f;
0359         qreal factorHeight = printSize.isValid() ? ( printSize.height() / m_chart->rect().height() ) : 1.0f;
0360         ma.setMarkerSize( QSize( markersWidthSB->value() * factorWidth, markersHeightSB->value() * factorHeight ) );
0361 
0362         dva.setMarkerAttributes( ma );
0363         m_lines->setDataValueAttributes( iColumn, dva );
0364 
0365         // make a special one for certain values
0366         DataValueAttributes yellowAttributes( dva );
0367         MarkerAttributes yellowMarker( yellowAttributes.markerAttributes() );
0368         yellowMarker.setMarkerColor( Qt::yellow );
0369         yellowAttributes.setMarkerAttributes( yellowMarker );
0370 
0371         const int rowCount = m_lines->model()->rowCount();
0372         for ( int j = 0; j < rowCount; ++j ) {
0373             QModelIndex index = m_lines->model()->index( j, iColumn, QModelIndex() );
0374             QBrush brush = m_lines->model()->headerData( iColumn, Qt::Vertical, DatasetBrushRole ).value<QBrush>();
0375             qreal value = m_lines->model()->data( index ).toReal();
0376             /* Set a specific color - marker for a specific value */
0377             if ( value == 13 ) {
0378                 m_lines->setDataValueAttributes( index, yellowAttributes );
0379             }
0380         }
0381     }
0382 }
0383 
0384 void MainWindow::on_savePB_clicked()
0385 {
0386     const QString file = QFileDialog::getSaveFileName( this, tr( "Choose PNG File..." ) );
0387     if ( file.isEmpty() )
0388         return;
0389     qDebug() << "Painting into PNG";
0390     QPixmap qpix( 600, 600 );
0391     QPainter painter( &qpix );
0392     painter.setBrush( Qt::white );
0393     painter.fillRect( 0, 0, 600, 600, Qt::white);
0394     m_chart->paint( &painter,
0395                     QRect( 100, 100, 400, 400 ) );
0396     painter.end();
0397     qpix.save( file, "PNG" );
0398     qDebug() << "Painting into PNG - done";
0399 }
0400 
0401 void MainWindow::on_savePDF_clicked()
0402 {
0403     const QString file = QFileDialog::getSaveFileName( this, tr( "Choose PDF File..." ) );
0404     if ( file.isEmpty() )
0405         return;
0406     qDebug() << "Painting into PDF";
0407     QPrinter printer( QPrinter::HighResolution );
0408     printer.setOrientation( QPrinter::Landscape );
0409     printer.setOutputFormat( QPrinter::PdfFormat );
0410     printer.setOutputFileName( file );
0411     paintMarkers( paintMarkersCB->isChecked(), printer.pageRect().size() );
0412     QPainter painter;
0413     painter.begin( &printer );
0414     m_chart->paint( &painter, printer.pageRect() );
0415     painter.end();
0416     paintMarkers( paintMarkersCB->isChecked(), m_chart->geometry().size() );
0417     qDebug() << "Painting into PDF - done";
0418 }
0419 
0420 void MainWindow::resizeEvent( QResizeEvent * )
0421 {
0422     m_smallChart1->move( width() - m_pix1.width() * 2,
0423                          height() / 2 - m_pix1.height() - 5 );
0424     m_smallChart2->move( width() - m_pix2.width() * 2,
0425                          height() / 2 + 5 );
0426 }