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 "KChartAbstractAxis.h"
21 #include "KChartAbstractAxis_p.h"
22 #include "KChartAbstractDiagram.h"
23 #include "KChartAbstractCartesianDiagram.h"
24 #include "KChartEnums.h"
25 #include "KChartMeasure.h"
26 #include "KChartMath_p.h"
27 
28 using namespace KChart;
29 
30 #define d d_func()
31 
Private(AbstractDiagram * diagram,AbstractAxis * axis)32 AbstractAxis::Private::Private( AbstractDiagram* diagram, AbstractAxis* axis )
33     : observer( nullptr )
34     , mDiagram( diagram )
35     , mAxis( axis )
36 {
37     // Note: We do NOT call setDiagram( diagram, axis );
38     //       but it is called in AbstractAxis::delayedInit() instead!
39 }
40 
~Private()41 AbstractAxis::Private::~Private()
42 {
43     delete observer;
44     observer = nullptr;
45 }
46 
setDiagram(AbstractDiagram * diagram_,bool delayedInit)47 bool AbstractAxis::Private::setDiagram( AbstractDiagram* diagram_, bool delayedInit )
48 {
49     AbstractDiagram* diagram = delayedInit ? mDiagram : diagram_;
50     if ( delayedInit ) {
51         mDiagram = nullptr;
52     }
53 
54     // do not set a diagram again that was already set
55     if ( diagram &&
56         ((diagram == mDiagram) || secondaryDiagrams.contains( diagram )) )
57         return false;
58 
59     bool bNewDiagramStored = false;
60     if ( ! mDiagram ) {
61         mDiagram = diagram;
62         delete observer;
63         if ( mDiagram ) {
64             observer = new DiagramObserver( mDiagram, mAxis );
65             const bool con = connect( observer, SIGNAL(diagramDataChanged(AbstractDiagram*)),
66                     mAxis, SIGNAL(coordinateSystemChanged()) );
67             Q_UNUSED( con )
68             Q_ASSERT( con );
69             bNewDiagramStored = true;
70         } else {
71             observer = nullptr;
72         }
73     } else {
74         if ( diagram )
75             secondaryDiagrams.enqueue( diagram );
76     }
77     return bNewDiagramStored;
78 }
79 
unsetDiagram(AbstractDiagram * diagram)80 void AbstractAxis::Private::unsetDiagram( AbstractDiagram* diagram )
81 {
82     if ( diagram == mDiagram ) {
83         mDiagram = nullptr;
84         delete observer;
85         observer = nullptr;
86     } else {
87         secondaryDiagrams.removeAll( diagram );
88     }
89     if ( !secondaryDiagrams.isEmpty() ) {
90         AbstractDiagram *nextDiagram = secondaryDiagrams.dequeue();
91         setDiagram( nextDiagram );
92     }
93 }
94 
hasDiagram(AbstractDiagram * diagram) const95 bool AbstractAxis::Private::hasDiagram( AbstractDiagram* diagram ) const
96 {
97     return diagram == mDiagram || secondaryDiagrams.contains( diagram );
98 }
99 
updateLayouts()100 void AbstractAxis::Private::updateLayouts()
101 {
102     if ( CartesianAxis* cartesianAxis = qobject_cast< CartesianAxis* >( mAxis ) ) {
103         cartesianAxis->layoutPlanes();
104     } else {
105         mAxis->update();
106     }
107 }
108 
AbstractAxis(AbstractDiagram * diagram)109 AbstractAxis::AbstractAxis ( AbstractDiagram* diagram )
110     : AbstractArea( new Private( diagram, this ) )
111 {
112     init();
113     QTimer::singleShot(0, this, SLOT(delayedInit()));
114 }
115 
~AbstractAxis()116 AbstractAxis::~AbstractAxis()
117 {
118     d->mDiagram = nullptr;
119     d->secondaryDiagrams.clear();
120 }
121 
122 
init()123 void AbstractAxis::init()
124 {
125     Measure m( 14, KChartEnums::MeasureCalculationModeAuto, KChartEnums::MeasureOrientationAuto );
126     d->textAttributes.setFontSize( m );
127     m.setValue( 6 );
128     m.setCalculationMode( KChartEnums::MeasureCalculationModeAbsolute );
129     d->textAttributes.setMinimalFontSize( m );
130     if ( d->diagram() )
131         createObserver( d->diagram() );
132 }
133 
delayedInit()134 void AbstractAxis::delayedInit()
135 {
136     // We call setDiagram() here, because the c'tor of Private
137     // only has stored the pointers, but it did not call setDiagram().
138     if ( d )
139         d->setDiagram( nullptr, true /* delayedInit */ );
140 }
141 
compare(const AbstractAxis * other) const142 bool AbstractAxis::compare( const AbstractAxis* other ) const
143 {
144     if ( other == this ) {
145         return true;
146     }
147     if ( !other ) {
148         return false;
149     }
150 
151     return  ( static_cast<const AbstractAreaBase*>(this)->compare( other ) ) &&
152             (textAttributes() == other->textAttributes()) &&
153             (labels()         == other->labels()) &&
154             (shortLabels()    == other->shortLabels());
155 }
156 
157 
customizedLabel(const QString & label) const158 const QString AbstractAxis::customizedLabel( const QString& label ) const
159 {
160     return label;
161 }
162 
163 
createObserver(AbstractDiagram * diagram)164 void AbstractAxis::createObserver( AbstractDiagram* diagram )
165 {
166     d->setDiagram( diagram );
167 }
168 
deleteObserver(AbstractDiagram * diagram)169 void AbstractAxis::deleteObserver( AbstractDiagram* diagram )
170 {
171     d->unsetDiagram( diagram );
172 }
173 
connectSignals()174 void AbstractAxis::connectSignals()
175 {
176     if ( d->observer ) {
177         const bool con = connect( d->observer, SIGNAL(diagramDataChanged(AbstractDiagram*)),
178                 this, SIGNAL(coordinateSystemChanged()) );
179         Q_UNUSED( con );
180         Q_ASSERT( con );
181     }
182 }
183 
setTextAttributes(const TextAttributes & a)184 void AbstractAxis::setTextAttributes( const TextAttributes &a )
185 {
186     if ( d->textAttributes == a )
187         return;
188 
189     d->textAttributes = a;
190     d->updateLayouts();
191 }
192 
textAttributes() const193 TextAttributes AbstractAxis::textAttributes() const
194 {
195     return d->textAttributes;
196 }
197 
198 
setRulerAttributes(const RulerAttributes & a)199 void AbstractAxis::setRulerAttributes( const RulerAttributes &a )
200 {
201     d->rulerAttributes = a;
202     d->updateLayouts();
203 }
204 
rulerAttributes() const205 RulerAttributes AbstractAxis::rulerAttributes() const
206 {
207     return d->rulerAttributes;
208 }
209 
setLabels(const QStringList & list)210 void AbstractAxis::setLabels( const QStringList& list )
211 {
212     if ( d->hardLabels == list )
213         return;
214 
215     d->hardLabels = list;
216     d->updateLayouts();
217 }
218 
labels() const219 QStringList AbstractAxis::labels() const
220 {
221     return d->hardLabels;
222 }
223 
setShortLabels(const QStringList & list)224 void AbstractAxis::setShortLabels( const QStringList& list )
225 {
226     if ( d->hardShortLabels == list )
227         return;
228 
229     d->hardShortLabels = list;
230     d->updateLayouts();
231 }
232 
shortLabels() const233 QStringList AbstractAxis::shortLabels() const
234 {
235     return d->hardShortLabels;
236 }
237 
coordinatePlane() const238 const AbstractCoordinatePlane* AbstractAxis::coordinatePlane() const
239 {
240     if ( d->diagram() )
241         return d->diagram()->coordinatePlane();
242     return nullptr;
243 }
244 
diagram() const245 const AbstractDiagram * KChart::AbstractAxis::diagram() const
246 {
247     return d->diagram();
248 }
249 
observedBy(AbstractDiagram * diagram) const250 bool KChart::AbstractAxis::observedBy( AbstractDiagram * diagram ) const
251 {
252     return d->hasDiagram( diagram );
253 }
254 
update()255 void KChart::AbstractAxis::update()
256 {
257     if ( d->diagram() )
258         d->diagram()->update();
259 }
260