1 /**
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "datavaluesettings.h"
21 #include "ui_datavaluesettings.h"
22 
23 #include <KChartChart>
24 #include <KChartAbstractCoordinatePlane>
25 #include <KChartBarDiagram>
26 #include <KChartTextAttributes>
27 #include <KChartRelativePosition>
28 #include <KChartPosition>
29 #include <KChartDataValueAttributes>
30 #include <KChartAbstractDiagram>
31 
32 
33 #include <QDebug>
34 #include <QPainter>
35 
36 using namespace KChart;
37 
38 class DataValueSettings::Private : public QObject
39 {
40     Q_OBJECT
41 public:
42     Private( KChart::Chart *chart, DataValueSettings *q );
43     DataValueSettings *qq;
44     void init();
45 public Q_SLOTS:
46     void on_scopeOneBarRB_toggled(  bool checked );
47     void on_scopeBarDatasetSB_valueChanged( int i );
48     void on_scopeBarItemSB_valueChanged(    int i );
49     void on_scopeDatasetRB_toggled( bool checked );
50     void on_scopeDatasetSB_valueChanged( int i );
51     void on_scopeCommonRB_toggled( bool checked );
52 
53     void on_paintValuesCB_toggled( bool checked );
54 
55     void on_fontCombo_currentIndexChanged( const QString & text );
56     void on_relativeSizeSB_valueChanged( int i );
57     void on_minimumSizeSB_valueChanged(  int i );
58     void on_rotationSB_valueChanged( int i );
59 
60     void on_posPosCombo_currentIndexChanged(   const QString & text );
61     void on_posAlignCombo_currentIndexChanged( const QString & text );
62     void on_posPadHoriSB_valueChanged( int i );
63     void on_posPadVertSB_valueChanged( int i );
64     void on_negPosCombo_currentIndexChanged(   const QString & text );
65     void on_negAlignCombo_currentIndexChanged( const QString & text );
66     void on_negPadHoriSB_valueChanged( int i );
67     void on_negPadVertSB_valueChanged( int i );
68 
69     void on_labelLE_textEdited(  const QString & text );
70     void on_prefixLE_textEdited( const QString & text );
71     void on_suffixLE_textEdited( const QString & text );
72 public:
73     const QModelIndex currentIndex() const;
74     const KChart::DataValueAttributes attributes() const;
75     const char* positionToScreenName( const KChart::Position& pos ) const;
76     const Qt::Alignment alignmentFromScreeName( const QString& name ) const;
77     const QString alignmentToScreenName( const Qt::Alignment& align ) const;
78     void populateWidgets();
79     void setAttributes( const KChart::DataValueAttributes& da );
80     void connectWidgets();
81 
82     KChart::Chart* m_chart;
83     Ui::DataValueSettings *ui;
84 };
85 
Private(KChart::Chart * chart,DataValueSettings * q)86 DataValueSettings::Private::Private( KChart::Chart *chart, DataValueSettings *q )
87     : qq ( q )
88     , m_chart( chart )
89     , ui( new Ui::DataValueSettings )
90 {
91 
92 }
93 
init()94 void DataValueSettings::Private::init()
95 {
96     ui->setupUi( qq );
97     ui->scopeCommonRB->setFocus( Qt::OtherFocusReason );
98     ui->scopeCommonRB->setChecked( true );
99     ui->paintValuesCB->setChecked( true );
100     populateWidgets();
101     connectWidgets();
102 }
103 
connectWidgets()104 void DataValueSettings::Private::connectWidgets()
105 {
106     connect( ui->scopeBarDatasetSB, SIGNAL(valueChanged(int)), this, SLOT(on_scopeBarDatasetSB_valueChanged(int)) );
107     connect( ui->scopeBarItemSB, SIGNAL(valueChanged(int)), this, SLOT(on_scopeBarItemSB_valueChanged(int)) );
108     connect( ui->scopeDatasetSB, SIGNAL(valueChanged(int)), this, SLOT(on_scopeDatasetSB_valueChanged(int)) );
109     connect( ui->scopeOneBarRB, SIGNAL(toggled(bool)), this, SLOT(on_scopeOneBarRB_toggled(bool)) );
110     connect( ui->scopeDatasetRB, SIGNAL(toggled(bool)), this, SLOT(on_scopeDatasetRB_toggled(bool)) );
111     connect( ui->scopeCommonRB, SIGNAL(toggled(bool)), this, SLOT(on_scopeCommonRB_toggled(bool)) );
112     connect( ui->paintValuesCB, SIGNAL(toggled(bool)), this, SLOT(on_paintValuesCB_toggled(bool)) );
113     connect( ui->fontCombo, SIGNAL(currentIndexChanged(QString)), this , SLOT(on_fontCombo_currentIndexChanged(QString)) );
114     connect( ui->relativeSizeSB, SIGNAL(valueChanged(int)), this, SLOT(on_relativeSizeSB_valueChanged(int)) );
115     connect( ui->minimumSizeSB, SIGNAL(valueChanged(int)), this, SLOT(on_minimumSizeSB_valueChanged(int)) );
116     connect( ui->rotationSB, SIGNAL(valueChanged(int)), this, SLOT(on_rotationSB_valueChanged(int)) );
117     connect( ui->posPosCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_posPosCombo_currentIndexChanged(QString)) );
118     connect( ui->posAlignCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_posAlignCombo_currentIndexChanged(QString)) );
119     connect( ui->posPadHoriSB, SIGNAL(valueChanged(int)), this, SLOT(on_posPadHoriSB_valueChanged(int)) );
120     connect( ui->posPadVertSB, SIGNAL(valueChanged(int)), this, SLOT(on_posPadVertSB_valueChanged(int)) );
121     connect( ui->negPosCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_negPosCombo_currentIndexChanged(QString)) );
122     connect( ui->negAlignCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_negAlignCombo_currentIndexChanged(QString)) );
123     connect( ui->negPadHoriSB, SIGNAL(valueChanged(int)), this, SLOT(on_negPadHoriSB_valueChanged(int)) );
124     connect( ui->negPadVertSB, SIGNAL(valueChanged(int)), this, SLOT(on_negPadVertSB_valueChanged(int)) );
125     connect( ui->labelLE, SIGNAL(textEdited(QString)), this, SLOT(on_labelLE_textEdited(QString)) );
126     connect( ui->prefixLE, SIGNAL(textEdited(QString)), this, SLOT(on_prefixLE_textEdited(QString)) );
127     connect( ui->suffixLE, SIGNAL(textEdited(QString)), this, SLOT(on_suffixLE_textEdited(QString)) );
128 }
129 
DataValueSettings(KChart::Chart * chart,QWidget * parent)130 DataValueSettings::DataValueSettings( KChart::Chart *chart, QWidget* parent )
131     : QWidget( parent )
132     , d( new Private( chart, this ) )
133 {
134     d->init();
135 }
136 
~DataValueSettings()137 DataValueSettings::~DataValueSettings()
138 {
139     delete d;
140 }
141 
refresh()142 void DataValueSettings::refresh()
143 {
144     d->populateWidgets();
145 }
146 
147 
on_scopeOneBarRB_toggled(bool checked)148 void DataValueSettings::Private::on_scopeOneBarRB_toggled(  bool checked )
149 {
150     if ( checked ) {
151         ui->scopeBarDatasetSB->setDisabled( false );
152         ui->scopeBarItemSB->setDisabled( false );
153         ui->scopeDatasetSB->setDisabled( true );
154         populateWidgets();
155     }
156 }
157 
on_scopeBarDatasetSB_valueChanged(int i)158 void DataValueSettings::Private::on_scopeBarDatasetSB_valueChanged( int i )
159 {
160     Q_UNUSED(i)
161     populateWidgets();
162 }
163 
on_scopeBarItemSB_valueChanged(int i)164 void DataValueSettings::Private::on_scopeBarItemSB_valueChanged( int i )
165 {
166     Q_UNUSED(i)
167     populateWidgets();
168 }
169 
on_scopeDatasetRB_toggled(bool checked)170 void DataValueSettings::Private::on_scopeDatasetRB_toggled( bool checked )
171 {
172     if ( checked ) {
173         ui->scopeBarDatasetSB->setDisabled( true );
174         ui->scopeBarItemSB->setDisabled( true );
175         ui->scopeDatasetSB->setDisabled( false );
176         populateWidgets();
177     }
178 }
179 
on_scopeDatasetSB_valueChanged(int i)180 void DataValueSettings::Private::on_scopeDatasetSB_valueChanged( int i )
181 {
182     Q_UNUSED(i)
183     populateWidgets();
184 }
185 
on_scopeCommonRB_toggled(bool checked)186 void DataValueSettings::Private::on_scopeCommonRB_toggled( bool checked )
187 {
188     if ( checked ) {
189         ui->scopeBarDatasetSB->setDisabled( true );
190         ui->scopeBarItemSB->setDisabled( true );
191         ui->scopeDatasetSB->setDisabled( true );
192         populateWidgets();
193     }
194 }
195 
on_paintValuesCB_toggled(bool checked)196 void DataValueSettings::Private::on_paintValuesCB_toggled( bool checked )
197 {
198     DataValueAttributes da( attributes() );
199     da.setVisible( checked );
200     setAttributes( da );
201 
202     m_chart->update();
203 }
204 
on_fontCombo_currentIndexChanged(const QString & text)205 void DataValueSettings::Private::on_fontCombo_currentIndexChanged( const QString & text )
206 {
207     DataValueAttributes da( attributes() );
208     TextAttributes ta( da.textAttributes() );
209     QFont font( text );
210     ta.setFont( font );
211     da.setTextAttributes( ta );
212     setAttributes( da );
213 
214     m_chart->update();
215 }
216 
on_relativeSizeSB_valueChanged(int i)217 void DataValueSettings::Private::on_relativeSizeSB_valueChanged( int i )
218 {
219     DataValueAttributes da( attributes() );
220     TextAttributes ta( da.textAttributes() );
221     Measure fs( ta.fontSize() );
222     fs.setValue( i );
223     ta.setFontSize( i );
224     da.setTextAttributes( ta );
225     setAttributes( da );
226 
227     m_chart->update();
228 }
229 
on_minimumSizeSB_valueChanged(int i)230 void DataValueSettings::Private::on_minimumSizeSB_valueChanged( int i )
231 {
232     DataValueAttributes da( attributes() );
233     TextAttributes ta( da.textAttributes() );
234     Measure fs( ta.fontSize() );
235     fs.setValue( i );
236     ta.setMinimalFontSize( i );
237     da.setTextAttributes( ta );
238     setAttributes( da );
239 
240     m_chart->update();
241 }
242 
on_rotationSB_valueChanged(int i)243 void DataValueSettings::Private::on_rotationSB_valueChanged( int i )
244 {
245     DataValueAttributes da( attributes() );
246     TextAttributes ta( da.textAttributes() );
247     ta.setRotation( i );
248     da.setTextAttributes( ta );
249     setAttributes( da );
250 
251     m_chart->update();
252 }
253 
on_posPosCombo_currentIndexChanged(const QString & text)254 void DataValueSettings::Private::on_posPosCombo_currentIndexChanged( const QString & text )
255 {
256     DataValueAttributes da( attributes() );
257     RelativePosition relPos( da.positivePosition() );
258     relPos.setReferencePosition( Position::fromName( qPrintable( text ) ) );
259     da.setPositivePosition( relPos );
260     setAttributes( da );
261 
262     m_chart->update();
263 }
264 
on_posAlignCombo_currentIndexChanged(const QString & text)265 void DataValueSettings::Private::on_posAlignCombo_currentIndexChanged( const QString & text )
266 {
267     DataValueAttributes da( attributes() );
268     RelativePosition relPos( da.positivePosition() );
269     relPos.setAlignment( alignmentFromScreeName( text ) );
270     da.setPositivePosition( relPos );
271     setAttributes( da );
272 
273     m_chart->update();
274 }
275 
on_posPadHoriSB_valueChanged(int i)276 void DataValueSettings::Private::on_posPadHoriSB_valueChanged( int i )
277 {
278     DataValueAttributes da( attributes() );
279     RelativePosition relPos( da.positivePosition() );
280     Measure pad( relPos.horizontalPadding() );
281     pad.setValue( i );
282     relPos.setHorizontalPadding( pad );
283     da.setPositivePosition( relPos );
284     setAttributes( da );
285 
286     m_chart->update();
287 }
288 
on_posPadVertSB_valueChanged(int i)289 void DataValueSettings::Private::on_posPadVertSB_valueChanged( int i )
290 {
291     DataValueAttributes da( attributes() );
292     RelativePosition relPos( da.positivePosition() );
293     Measure pad( relPos.verticalPadding() );
294     pad.setValue( i );
295     relPos.setVerticalPadding( pad );
296     da.setPositivePosition( relPos );
297     setAttributes( da );
298 
299     m_chart->update();
300 }
301 
on_negPosCombo_currentIndexChanged(const QString & text)302 void DataValueSettings::Private::on_negPosCombo_currentIndexChanged( const QString & text )
303 {
304     DataValueAttributes da( attributes() );
305     RelativePosition relPos( da.negativePosition() );
306     relPos.setReferencePosition( Position::fromName( qPrintable( text ) ) );
307     da.setNegativePosition( relPos );
308     setAttributes( da );
309 
310     m_chart->update();
311 }
312 
on_negAlignCombo_currentIndexChanged(const QString & text)313 void DataValueSettings::Private::on_negAlignCombo_currentIndexChanged( const QString & text )
314 {
315     DataValueAttributes da( attributes() );
316     RelativePosition relPos( da.negativePosition() );
317     relPos.setAlignment( alignmentFromScreeName( text ) );
318     da.setNegativePosition( relPos );
319     setAttributes( da );
320 
321     m_chart->update();
322 }
323 
on_negPadHoriSB_valueChanged(int i)324 void DataValueSettings::Private::on_negPadHoriSB_valueChanged( int i )
325 {
326     DataValueAttributes da( attributes() );
327     RelativePosition relPos( da.negativePosition() );
328     Measure pad( relPos.horizontalPadding() );
329     pad.setValue( i );
330     relPos.setHorizontalPadding( pad );
331     da.setNegativePosition( relPos );
332     setAttributes( da );
333 
334     m_chart->update();
335 }
336 
on_negPadVertSB_valueChanged(int i)337 void DataValueSettings::Private::on_negPadVertSB_valueChanged( int i )
338 {
339     DataValueAttributes da( attributes() );
340     RelativePosition relPos( da.negativePosition() );
341     Measure pad( relPos.verticalPadding() );
342     pad.setValue( i );
343     relPos.setVerticalPadding( pad );
344     da.setNegativePosition( relPos );
345     setAttributes( da );
346 
347     m_chart->update();
348 }
349 
on_labelLE_textEdited(const QString & text)350 void DataValueSettings::Private::on_labelLE_textEdited( const QString & text )
351 {
352     DataValueAttributes da( attributes() );
353     da.setDataLabel( text.isEmpty() ? QString() : text );
354     setAttributes( da );
355 
356     m_chart->update();
357 }
358 
on_prefixLE_textEdited(const QString & text)359 void DataValueSettings::Private::on_prefixLE_textEdited( const QString & text )
360 {
361     DataValueAttributes da( attributes() );
362     da.setPrefix( text.isEmpty() ? QString() : text );
363     setAttributes( da );
364 
365     m_chart->update();
366 }
367 
on_suffixLE_textEdited(const QString & text)368 void DataValueSettings::Private::on_suffixLE_textEdited( const QString & text )
369 {
370     DataValueAttributes da( attributes() );
371     da.setSuffix( text.isEmpty() ? QString() : text );
372     setAttributes( da );
373 
374     m_chart->update();
375 }
376 
currentIndex() const377 const QModelIndex DataValueSettings::Private::currentIndex() const
378 {
379     const int dataset = ui->scopeBarDatasetSB->value();
380     const int item    = ui->scopeBarItemSB->value();
381     Q_ASSERT( m_chart );
382     Q_ASSERT( m_chart->coordinatePlane() );
383     AbstractDiagram *diag = m_chart->coordinatePlane()->diagram();
384     return diag->model()->index( item, dataset, QModelIndex() );
385 }
386 
attributes() const387 const KChart::DataValueAttributes DataValueSettings::Private::attributes() const
388 {
389     Q_ASSERT( m_chart );
390     Q_ASSERT( m_chart->coordinatePlane() );
391     AbstractDiagram *diag = m_chart->coordinatePlane()->diagram();
392     DataValueAttributes attr = diag->dataValueAttributes();
393     if ( ui->scopeOneBarRB->isChecked() ) {
394         attr = diag->dataValueAttributes( currentIndex() );
395     }
396     else if ( ui->scopeDatasetRB->isChecked() ) {
397         attr = diag->dataValueAttributes( ui->scopeDatasetSB->value() );
398     }
399     attr.setShowRepetitiveDataLabels( true );
400     return attr;
401 }
402 
setAttributes(const KChart::DataValueAttributes & da)403 void DataValueSettings::Private::setAttributes( const KChart::DataValueAttributes& da )
404 {
405     Q_ASSERT( m_chart );
406     Q_ASSERT( m_chart->coordinatePlane() );
407     AbstractDiagram *diag = m_chart->coordinatePlane()->diagram();
408     if ( ui->scopeOneBarRB->isChecked() )
409         diag->setDataValueAttributes( currentIndex(), da );
410     else if ( ui->scopeDatasetRB->isChecked() )
411         diag->setDataValueAttributes( ui->scopeDatasetSB->value(), da );
412     else
413         diag->setDataValueAttributes( da );
414 }
415 
416 // just a convenience method:
417 // In the combo box we have the text "( Default Value )" instead of "Unknown Position"
418 // because by setting a position to unknown we get KD Chart to use the
419 // diagram-specific default positions.
positionToScreenName(const Position & pos) const420 const char* DataValueSettings::Private::positionToScreenName( const Position& pos ) const
421 {
422     static const char* defaultPositionName = "( Default Value )";
423     if ( pos.isUnknown() )
424         return defaultPositionName;
425     return pos.name();
426 }
427 
alignmentFromScreeName(const QString & name) const428 const Qt::Alignment DataValueSettings::Private::alignmentFromScreeName( const QString& name ) const
429 {
430     if ( name == "Center" )      return Qt::AlignCenter;
431     if ( name == "BottomLeft" )  return Qt::AlignLeft    | Qt::AlignBottom;
432     if ( name == "Bottom" )      return Qt::AlignHCenter | Qt::AlignBottom;
433     if ( name == "BottomRight" ) return Qt::AlignRight   | Qt::AlignBottom;
434     if ( name == "Right" )       return Qt::AlignRight   | Qt::AlignVCenter;
435     if ( name == "TopRight" )    return Qt::AlignRight   | Qt::AlignTop;
436     if ( name == "Top" )         return Qt::AlignHCenter | Qt::AlignTop;
437     if ( name == "TopLeft" )     return Qt::AlignLeft    | Qt::AlignTop;
438     if ( name == "Left" )        return Qt::AlignLeft    | Qt::AlignVCenter;
439     return Qt::AlignCenter;
440 }
441 
alignmentToScreenName(const Qt::Alignment & align) const442 const QString DataValueSettings::Private::alignmentToScreenName( const Qt::Alignment& align ) const
443 {
444     if ( align == Qt::AlignCenter )                       return "Center";
445     if ( align == (Qt::AlignLeft    | Qt::AlignBottom) )  return "BottomLeft";
446     if ( align == (Qt::AlignHCenter | Qt::AlignBottom) )  return "Bottom";
447     if ( align == (Qt::AlignRight   | Qt::AlignBottom) )  return "BottomRight";
448     if ( align == (Qt::AlignRight   | Qt::AlignVCenter) ) return "Right";
449     if ( align == (Qt::AlignRight   | Qt::AlignTop) )     return "TopRight";
450     if ( align == (Qt::AlignHCenter | Qt::AlignTop) )     return "Top";
451     if ( align == (Qt::AlignLeft    | Qt::AlignTop) )     return "TopLeft";
452     if ( align == (Qt::AlignLeft    | Qt::AlignVCenter) ) return "Left";
453     return "Center";
454 }
455 
populateWidgets()456 void DataValueSettings::Private::populateWidgets()
457 {
458     const DataValueAttributes da( attributes() );
459     const TextAttributes ta( da.textAttributes() );
460     const RelativePosition posPos( da.positivePosition() );
461     const RelativePosition negPos( da.negativePosition() );
462 
463     ui->paintValuesCB->setChecked( da.isVisible() && ta.isVisible() );
464     ui->fontCombo->setCurrentFont( ta.font() );
465     ui->relativeSizeSB->setValue( static_cast<int>(ta.fontSize().value()) );
466     ui->minimumSizeSB->setValue( static_cast<int>(ta.minimalFontSize().value()) );
467     ui->rotationSB->setValue( static_cast<int>(ta.rotation()) );
468 
469     ui->posPosCombo->setCurrentIndex( ui->posPosCombo->findText(
470             positionToScreenName( posPos.referencePosition() ) ) );
471     ui->posAlignCombo->setCurrentIndex( ui->posAlignCombo->findText(
472             alignmentToScreenName( posPos.alignment() ) ) );
473     ui->posPadHoriSB->setValue( static_cast<int>(posPos.horizontalPadding().value()) );
474     ui->posPadVertSB->setValue( static_cast<int>(posPos.verticalPadding().value()) );
475 
476     ui->negPosCombo->setCurrentIndex( ui->negPosCombo->findText( positionToScreenName(
477             negPos.referencePosition() ) ) );
478     ui->negAlignCombo->setCurrentIndex( ui->negAlignCombo->findText(
479             alignmentToScreenName( negPos.alignment() ) ) );
480     ui->negPadHoriSB->setValue( static_cast<int>(negPos.horizontalPadding().value()) );
481     ui->negPadVertSB->setValue( static_cast<int>(negPos.verticalPadding().value()) );
482 
483     ui->labelLE->setText( da.dataLabel() );
484     ui->prefixLE->setText( da.prefix() );
485     ui->suffixLE->setText( da.suffix() );
486 }
487 
488 #include "datavaluesettings.moc"
489