1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997   Josef Wilgen
4  * Copyright (C) 2002   Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include <qpainter.h>
11 #if QT_VERSION < 0x040000
12 #include <qguardedptr.h>
13 #include <qfocusdata.h>
14 #else
15 #include <qpointer.h>
16 #include <qpaintengine.h>
17 #endif
18 #include <qapplication.h>
19 #include <qevent.h>
20 #include "qwt_plot.h"
21 #include "qwt_plot_dict.h"
22 #include "qwt_plot_layout.h"
23 #include "qwt_scale_widget.h"
24 #include "qwt_scale_engine.h"
25 #include "qwt_text_label.h"
26 #include "qwt_legend.h"
27 #include "qwt_dyngrid_layout.h"
28 #include "qwt_plot_canvas.h"
29 #include "qwt_paint_buffer.h"
30 
31 class QwtPlot::PrivateData
32 {
33 public:
34 #if QT_VERSION < 0x040000
35     QGuardedPtr<QwtTextLabel> lblTitle;
36     QGuardedPtr<QwtPlotCanvas> canvas;
37     QGuardedPtr<QwtLegend> legend;
38 #else
39     QPointer<QwtTextLabel> lblTitle;
40     QPointer<QwtPlotCanvas> canvas;
41     QPointer<QwtLegend> legend;
42 #endif
43     QwtPlotLayout *layout;
44 
45     bool autoReplot;
46 };
47 
48 /*!
49   \brief Constructor
50   \param parent Parent widget
51  */
QwtPlot(QWidget * parent)52 QwtPlot::QwtPlot(QWidget *parent):
53     QFrame(parent)
54 {
55     initPlot(QwtText());
56 }
57 
58 /*!
59   \brief Constructor
60   \param title Title text
61   \param parent Parent widget
62  */
QwtPlot(const QwtText & title,QWidget * parent)63 QwtPlot::QwtPlot(const QwtText &title, QWidget *parent):
64     QFrame(parent)
65 {
66     initPlot(title);
67 }
68 
69 #if QT_VERSION < 0x040000
70 /*!
71   \brief Constructor
72   \param parent Parent widget
73   \param name Object name
74  */
QwtPlot(QWidget * parent,const char * name)75 QwtPlot::QwtPlot(QWidget *parent, const char *name):
76     QFrame(parent, name)
77 {
78     initPlot(QwtText());
79 }
80 #endif
81 
82 
83 //! Destructor
~QwtPlot()84 QwtPlot::~QwtPlot()
85 {
86     detachItems(QwtPlotItem::Rtti_PlotItem, autoDelete());
87 
88     delete d_data->layout;
89     deleteAxesData();
90     delete d_data;
91 }
92 
93 /*!
94   \brief Initializes a QwtPlot instance
95   \param title Title text
96  */
initPlot(const QwtText & title)97 void QwtPlot::initPlot(const QwtText &title)
98 {
99     d_data = new PrivateData;
100 
101 #if QT_VERSION < 0x040000
102     setWFlags(Qt::WNoAutoErase);
103 #endif
104 
105     d_data->layout = new QwtPlotLayout;
106 
107     d_data->autoReplot = false;
108 
109     d_data->lblTitle = new QwtTextLabel(title, this);
110     d_data->lblTitle->setFont(QFont(fontInfo().family(), 14, QFont::Bold));
111 
112     QwtText text(title);
113     int flags = Qt::AlignCenter;
114 #if QT_VERSION < 0x040000
115     flags |= Qt::WordBreak | Qt::ExpandTabs;
116 #else
117     flags |= Qt::TextWordWrap;
118 #endif
119     text.setRenderFlags(flags);
120     d_data->lblTitle->setText(text);
121 
122     d_data->legend = NULL;
123 
124     initAxesData();
125 
126     d_data->canvas = new QwtPlotCanvas(this);
127     d_data->canvas->setFrameStyle(QFrame::Panel|QFrame::Sunken);
128     d_data->canvas->setLineWidth(2);
129     d_data->canvas->setMidLineWidth(0);
130 
131     updateTabOrder();
132 
133     setSizePolicy(QSizePolicy::MinimumExpanding,
134         QSizePolicy::MinimumExpanding);
135 
136     resize( 200, 200 );
137 }
138 
139 /*!
140   \brief Adds handling of layout requests
141 */
event(QEvent * e)142 bool QwtPlot::event(QEvent *e)
143 {
144     bool ok = QFrame::event(e);
145     switch(e->type())
146     {
147 #if QT_VERSION < 0x040000
148         case QEvent::LayoutHint:
149 #else
150         case QEvent::LayoutRequest:
151 #endif
152             updateLayout();
153             break;
154 #if QT_VERSION >= 0x040000
155         case QEvent::PolishRequest:
156             polish();
157             break;
158 #endif
159         default:;
160     }
161     return ok;
162 }
163 
164 //! Replots the plot if QwtPlot::autoReplot() is \c true.
autoRefresh()165 void QwtPlot::autoRefresh()
166 {
167     if (d_data->autoReplot)
168         replot();
169 }
170 
171 /*!
172   \brief Set or reset the autoReplot option
173 
174   If the autoReplot option is set, the plot will be
175   updated implicitly by manipulating member functions.
176   Since this may be time-consuming, it is recommended
177   to leave this option switched off and call replot()
178   explicitly if necessary.
179 
180   The autoReplot option is set to false by default, which
181   means that the user has to call replot() in order to make
182   changes visible.
183   \param tf \c true or \c false. Defaults to \c true.
184   \sa replot()
185 */
setAutoReplot(bool tf)186 void QwtPlot::setAutoReplot(bool tf)
187 {
188     d_data->autoReplot = tf;
189 }
190 
191 //! \return true if the autoReplot option is set.
autoReplot() const192 bool QwtPlot::autoReplot() const
193 {
194     return d_data->autoReplot;
195 }
196 
197 /*!
198   Change the plot's title
199   \param title New title
200 */
setTitle(const QString & title)201 void QwtPlot::setTitle(const QString &title)
202 {
203     if ( title != d_data->lblTitle->text().text() )
204     {
205         d_data->lblTitle->setText(title);
206         updateLayout();
207     }
208 }
209 
210 /*!
211   Change the plot's title
212   \param title New title
213 */
setTitle(const QwtText & title)214 void QwtPlot::setTitle(const QwtText &title)
215 {
216     if ( title != d_data->lblTitle->text() )
217     {
218         d_data->lblTitle->setText(title);
219         updateLayout();
220     }
221 }
222 
223 //! \return the plot's title
title() const224 QwtText QwtPlot::title() const
225 {
226     return d_data->lblTitle->text();
227 }
228 
229 //! \return the plot's title
plotLayout()230 QwtPlotLayout *QwtPlot::plotLayout()
231 {
232     return d_data->layout;
233 }
234 
235 //! \return the plot's titel label.
plotLayout() const236 const QwtPlotLayout *QwtPlot::plotLayout() const
237 {
238     return d_data->layout;
239 }
240 
241 //! \return the plot's titel label.
titleLabel()242 QwtTextLabel *QwtPlot::titleLabel()
243 {
244     return d_data->lblTitle;
245 }
246 
247 /*!
248   \return the plot's titel label.
249 */
titleLabel() const250 const QwtTextLabel *QwtPlot::titleLabel() const
251 {
252     return d_data->lblTitle;
253 }
254 
255 /*!
256   \return the plot's legend
257   \sa insertLegend()
258 */
legend()259 QwtLegend *QwtPlot::legend()
260 {
261     return d_data->legend;
262 }
263 
264 /*!
265   \return the plot's legend
266   \sa insertLegend()
267 */
legend() const268 const QwtLegend *QwtPlot::legend() const
269 {
270     return d_data->legend;
271 }
272 
273 
274 /*!
275   \return the plot's canvas
276 */
canvas()277 QwtPlotCanvas *QwtPlot::canvas()
278 {
279     return d_data->canvas;
280 }
281 
282 /*!
283   \return the plot's canvas
284 */
canvas() const285 const QwtPlotCanvas *QwtPlot::canvas() const
286 {
287     return d_data->canvas;
288 }
289 
290 //! Polish
polish()291 void QwtPlot::polish()
292 {
293     replot();
294 
295 #if QT_VERSION < 0x040000
296     QFrame::polish();
297 #endif
298 }
299 
300 /*!
301   Return sizeHint
302   \sa minimumSizeHint()
303 */
304 
sizeHint() const305 QSize QwtPlot::sizeHint() const
306 {
307     int dw = 0;
308     int dh = 0;
309     for ( int axisId = 0; axisId < axisCnt; axisId++ )
310     {
311         if ( axisEnabled(axisId) )
312         {
313             const int niceDist = 40;
314             const QwtScaleWidget *scaleWidget = axisWidget(axisId);
315             const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv();
316             const int majCnt = scaleDiv.ticks(QwtScaleDiv::MajorTick).count();
317 
318             if ( axisId == yLeft || axisId == yRight )
319             {
320                 int hDiff = (majCnt - 1) * niceDist
321                     - scaleWidget->minimumSizeHint().height();
322                 if ( hDiff > dh )
323                     dh = hDiff;
324             }
325             else
326             {
327                 int wDiff = (majCnt - 1) * niceDist
328                     - scaleWidget->minimumSizeHint().width();
329                 if ( wDiff > dw )
330                     dw = wDiff;
331             }
332         }
333     }
334     return minimumSizeHint() + QSize(dw, dh);
335 }
336 
337 /*!
338   \brief Return a minimum size hint
339 */
minimumSizeHint() const340 QSize QwtPlot::minimumSizeHint() const
341 {
342     QSize hint = d_data->layout->minimumSizeHint(this);
343     hint += QSize(2 * frameWidth(), 2 * frameWidth());
344 
345     return hint;
346 }
347 
348 /*!
349   Resize and update internal layout
350   \param e Resize event
351 */
resizeEvent(QResizeEvent * e)352 void QwtPlot::resizeEvent(QResizeEvent *e)
353 {
354     QFrame::resizeEvent(e);
355     updateLayout();
356 }
357 
358 /*!
359   \brief Redraw the plot
360 
361   If the autoReplot option is not set (which is the default)
362   or if any curves are attached to raw data, the plot has to
363   be refreshed explicitly in order to make changes visible.
364 
365   \sa setAutoReplot()
366   \warning Calls canvas()->repaint, take care of infinite recursions
367 */
replot()368 void QwtPlot::replot()
369 {
370     bool doAutoReplot = autoReplot();
371     setAutoReplot(false);
372 
373     updateAxes();
374 
375     /*
376       Maybe the layout needs to be updated, because of changed
377       axes labels. We need to process them here before painting
378       to avoid that scales and canvas get out of sync.
379      */
380 #if QT_VERSION >= 0x040000
381     QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
382 #else
383     QApplication::sendPostedEvents(this, QEvent::LayoutHint);
384 #endif
385 
386     d_data->canvas->replot();
387 
388     setAutoReplot(doAutoReplot);
389 }
390 
391 /*!
392   \brief Adjust plot content to its current size.
393   \sa resizeEvent()
394 */
updateLayout()395 void QwtPlot::updateLayout()
396 {
397     d_data->layout->activate(this, contentsRect());
398 
399     //
400     // resize and show the visible widgets
401     //
402     if (!d_data->lblTitle->text().isEmpty())
403     {
404         d_data->lblTitle->setGeometry(d_data->layout->titleRect());
405         if (!d_data->lblTitle->isVisible())
406             d_data->lblTitle->show();
407     }
408     else
409         d_data->lblTitle->hide();
410 
411     for (int axisId = 0; axisId < axisCnt; axisId++ )
412     {
413         if (axisEnabled(axisId) )
414         {
415             axisWidget(axisId)->setGeometry(d_data->layout->scaleRect(axisId));
416 
417             if ( axisId == xBottom || axisId == xTop )
418             {
419                 QRegion r(d_data->layout->scaleRect(axisId));
420                 if ( axisEnabled(yLeft) )
421                     r = r.subtracted(QRegion(d_data->layout->scaleRect(yLeft)));
422                 if ( axisEnabled(yRight) )
423                     r = r.subtracted(QRegion(d_data->layout->scaleRect(yRight)));
424                 r.translate(-d_data->layout->scaleRect(axisId).x(),
425                     -d_data->layout->scaleRect(axisId).y());
426 
427                 axisWidget(axisId)->setMask(r);
428             }
429             if (!axisWidget(axisId)->isVisible())
430                 axisWidget(axisId)->show();
431         }
432         else
433             axisWidget(axisId)->hide();
434     }
435 
436     if ( d_data->legend &&
437         d_data->layout->legendPosition() != ExternalLegend )
438     {
439         if (d_data->legend->itemCount() > 0)
440         {
441             d_data->legend->setGeometry(d_data->layout->legendRect());
442             d_data->legend->show();
443         }
444         else
445             d_data->legend->hide();
446     }
447 
448     d_data->canvas->setGeometry(d_data->layout->canvasRect());
449 }
450 
451 /*!
452    Update the focus tab order
453 
454    The order is changed so that the canvas will be in front of the
455    first legend item, or behind the last legend item - depending
456    on the position of the legend.
457 */
458 
updateTabOrder()459 void QwtPlot::updateTabOrder()
460 {
461 #if QT_VERSION >= 0x040000
462     using namespace Qt; // QWidget::NoFocus/Qt::NoFocus
463 #else
464     if ( d_data->canvas->focusPolicy() == NoFocus )
465         return;
466 #endif
467     if ( d_data->legend.isNull()
468         || d_data->layout->legendPosition() == ExternalLegend
469         || d_data->legend->legendItems().count() == 0 )
470     {
471         return;
472     }
473 
474     // Depending on the position of the legend the
475     // tab order will be changed that the canvas is
476     // next to the last legend item, or before
477     // the first one.
478 
479     const bool canvasFirst =
480         d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
481         d_data->layout->legendPosition() == QwtPlot::RightLegend;
482 
483     QWidget *previous = NULL;
484 
485     QWidget *w;
486 #if QT_VERSION >= 0x040000
487     w = d_data->canvas;
488     while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
489 #else
490     if ( focusData() == NULL )
491         return;
492 
493     while ( focusData()->next() != d_data->canvas );
494     while ( (w = focusData()->next()) != d_data->canvas )
495 #endif
496     {
497         bool isLegendItem = false;
498         if ( w->focusPolicy() != NoFocus
499             && w->parent() && w->parent() == d_data->legend->contentsWidget() )
500         {
501             isLegendItem = true;
502         }
503 
504         if ( canvasFirst )
505         {
506             if ( isLegendItem )
507                 break;
508 
509             previous = w;
510         }
511         else
512         {
513             if ( isLegendItem )
514                 previous = w;
515             else
516             {
517                 if ( previous )
518                     break;
519             }
520         }
521     }
522 
523     if ( previous && previous != d_data->canvas)
524         setTabOrder(previous, d_data->canvas);
525 }
526 
527 /*!
528   Redraw the canvas.
529   \param painter Painter used for drawing
530 
531   \warning drawCanvas calls drawItems what is also used
532            for printing. Applications that like to add individual
533            plot items better overload drawItems()
534   \sa drawItems()
535 */
drawCanvas(QPainter * painter)536 void QwtPlot::drawCanvas(QPainter *painter)
537 {
538     QwtScaleMap maps[axisCnt];
539     for ( int axisId = 0; axisId < axisCnt; axisId++ )
540         maps[axisId] = canvasMap(axisId);
541 
542     drawItems(painter,
543         d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
544 }
545 
546 /*!
547   Redraw the canvas items.
548   \param painter Painter used for drawing
549   \param rect Bounding rectangle where to paint
550   \param map QwtPlot::axisCnt maps, mapping between plot and paint device coordinates
551   \param pfilter Plot print filter
552 */
553 
drawItems(QPainter * painter,const QRect & rect,const QwtScaleMap map[axisCnt],const QwtPlotPrintFilter & pfilter) const554 void QwtPlot::drawItems(QPainter *painter, const QRect &rect,
555         const QwtScaleMap map[axisCnt],
556         const QwtPlotPrintFilter &pfilter) const
557 {
558     const QwtPlotItemList& itmList = itemList();
559     for ( QwtPlotItemIterator it = itmList.begin();
560         it != itmList.end(); ++it )
561     {
562         QwtPlotItem *item = *it;
563         if ( item && item->isVisible() )
564         {
565             if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
566                 && item->rtti() == QwtPlotItem::Rtti_PlotGrid )
567             {
568                 continue;
569             }
570 
571             painter->save();
572 
573 #if QT_VERSION >= 0x040000
574             painter->setRenderHint(QPainter::Antialiasing,
575                 item->testRenderHint(QwtPlotItem::RenderAntialiased) );
576 #endif
577 
578             item->draw(painter,
579                 map[item->xAxis()], map[item->yAxis()],
580                 rect);
581 
582             painter->restore();
583         }
584     }
585 }
586 
587 /*!
588   \param axisId Axis
589   \return Map for the axis on the canvas. With this map pixel coordinates can
590           translated to plot coordinates and vice versa.
591   \sa QwtScaleMap, transform(), invTransform()
592 
593 */
canvasMap(int axisId) const594 QwtScaleMap QwtPlot::canvasMap(int axisId) const
595 {
596     QwtScaleMap map;
597     if ( !d_data->canvas )
598         return map;
599 
600     map.setTransformation(axisScaleEngine(axisId)->transformation());
601 
602     const QwtScaleDiv *sd = axisScaleDiv(axisId);
603     map.setScaleInterval(sd->lowerBound(), sd->upperBound());
604 
605     if ( axisEnabled(axisId) )
606     {
607         const QwtScaleWidget *s = axisWidget(axisId);
608         if ( axisId == yLeft || axisId == yRight )
609         {
610             int y = s->y() + s->startBorderDist() - d_data->canvas->y();
611             int h = s->height() - s->startBorderDist() - s->endBorderDist();
612             map.setPaintInterval(y + h, y);
613         }
614         else
615         {
616             int x = s->x() + s->startBorderDist() - d_data->canvas->x();
617             int w = s->width() - s->startBorderDist() - s->endBorderDist();
618             map.setPaintInterval(x, x + w);
619         }
620     }
621     else
622     {
623         const int margin = plotLayout()->canvasMargin(axisId);
624 
625         const QRect &canvasRect = d_data->canvas->contentsRect();
626         if ( axisId == yLeft || axisId == yRight )
627         {
628             map.setPaintInterval(canvasRect.bottom() - margin,
629                 canvasRect.top() + margin);
630         }
631         else
632         {
633             map.setPaintInterval(canvasRect.left() + margin,
634                 canvasRect.right() - margin);
635         }
636     }
637     return map;
638 }
639 
640 /*!
641   Change the margin of the plot. The margin is the space
642   around all components.
643 
644   \param margin new margin
645   \sa QwtPlotLayout::setMargin(), margin(), plotLayout()
646 */
setMargin(int margin)647 void QwtPlot::setMargin(int margin)
648 {
649     if ( margin < 0 )
650         margin = 0;
651 
652     if ( margin != d_data->layout->margin() )
653     {
654         d_data->layout->setMargin(margin);
655         updateLayout();
656     }
657 }
658 
659 /*!
660     \return margin
661     \sa setMargin(), QwtPlotLayout::margin(), plotLayout()
662 */
margin() const663 int QwtPlot::margin() const
664 {
665     return d_data->layout->margin();
666 }
667 
668 /*!
669   \brief Change the background of the plotting area
670 
671   Sets c to QColorGroup::Background of all colorgroups of
672   the palette of the canvas. Using canvas()->setPalette()
673   is a more powerful way to set these colors.
674   \param c new background color
675 */
setCanvasBackground(const QColor & c)676 void QwtPlot::setCanvasBackground(const QColor &c)
677 {
678     QPalette p = d_data->canvas->palette();
679 
680     for ( int i = 0; i < QPalette::NColorGroups; i++ )
681     {
682 #if QT_VERSION < 0x040000
683         p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
684 #else
685         p.setColor((QPalette::ColorGroup)i, QPalette::Window, c);
686 #endif
687     }
688 
689     canvas()->setPalette(p);
690 }
691 
692 /*!
693   Nothing else than: canvas()->palette().color(
694         QPalette::Normal, QColorGroup::Background);
695 
696   \return the background color of the plotting area.
697 */
canvasBackground() const698 const QColor & QwtPlot::canvasBackground() const
699 {
700 #if QT_VERSION < 0x040000
701     return canvas()->palette().color(
702         QPalette::Normal, QColorGroup::Background);
703 #else
704     return canvas()->palette().color(
705         QPalette::Normal, QPalette::Window);
706 #endif
707 }
708 
709 /*!
710   \brief Change the border width of the plotting area
711   Nothing else than canvas()->setLineWidth(w),
712   left for compatibility only.
713   \param w new border width
714 */
setCanvasLineWidth(int w)715 void QwtPlot::setCanvasLineWidth(int w)
716 {
717     canvas()->setLineWidth(w);
718     updateLayout();
719 }
720 
721 /*!
722   Nothing else than: canvas()->lineWidth(),
723   left for compatibility only.
724   \return the border width of the plotting area
725 */
canvasLineWidth() const726 int QwtPlot::canvasLineWidth() const
727 {
728     return canvas()->lineWidth();
729 }
730 
731 /*!
732   \return \c true if the specified axis exists, otherwise \c false
733   \param axisId axis index
734  */
axisValid(int axisId)735 bool QwtPlot::axisValid(int axisId)
736 {
737     return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
738 }
739 
740 /*!
741   Called internally when the legend has been clicked on.
742   Emits a legendClicked() signal.
743 */
legendItemClicked()744 void QwtPlot::legendItemClicked()
745 {
746     if ( d_data->legend && sender()->isWidgetType() )
747     {
748         QwtPlotItem *plotItem =
749             (QwtPlotItem*)d_data->legend->find((QWidget *)sender());
750         if ( plotItem )
751             emit legendClicked(plotItem);
752     }
753 }
754 
755 /*!
756   Called internally when the legend has been checked
757   Emits a legendClicked() signal.
758 */
legendItemChecked(bool on)759 void QwtPlot::legendItemChecked(bool on)
760 {
761     if ( d_data->legend && sender()->isWidgetType() )
762     {
763         QwtPlotItem *plotItem =
764             (QwtPlotItem*)d_data->legend->find((QWidget *)sender());
765         if ( plotItem )
766             emit legendChecked(plotItem, on);
767     }
768 }
769 
770 /*!
771    Remove all curves and markers
772    \deprecated Use QwtPlotDeict::detachItems instead
773 */
clear()774 void QwtPlot::clear()
775 {
776     detachItems(QwtPlotItem::Rtti_PlotCurve);
777     detachItems(QwtPlotItem::Rtti_PlotMarker);
778 }
779 
780 /*!
781   \brief Insert a legend
782 
783   If the position legend is \c QwtPlot::LeftLegend or \c QwtPlot::RightLegend
784   the legend will be organized in one column from top to down.
785   Otherwise the legend items will be placed in a table
786   with a best fit number of columns from left to right.
787 
788   If pos != QwtPlot::ExternalLegend the plot widget will become
789   parent of the legend. It will be deleted when the plot is deleted,
790   or another legend is set with insertLegend().
791 
792   \param legend Legend
793   \param pos The legend's position. For top/left position the number
794              of colums will be limited to 1, otherwise it will be set to
795              unlimited.
796 
797   \param ratio Ratio between legend and the bounding rect
798                of title, canvas and axes. The legend will be shrinked
799                if it would need more space than the given ratio.
800                The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
801                it will be reset to the default ratio.
802                The default vertical/horizontal ratio is 0.33/0.5.
803 
804   \sa legend(), QwtPlotLayout::legendPosition(),
805       QwtPlotLayout::setLegendPosition()
806 */
insertLegend(QwtLegend * legend,QwtPlot::LegendPosition pos,double ratio)807 void QwtPlot::insertLegend(QwtLegend *legend,
808     QwtPlot::LegendPosition pos, double ratio)
809 {
810     d_data->layout->setLegendPosition(pos, ratio);
811 
812     if ( legend != d_data->legend )
813     {
814         if ( d_data->legend && d_data->legend->parent() == this )
815             delete d_data->legend;
816 
817         d_data->legend = legend;
818 
819         if ( d_data->legend )
820         {
821             if ( pos != ExternalLegend )
822             {
823                 if ( d_data->legend->parent() != this )
824                 {
825 #if QT_VERSION < 0x040000
826                     d_data->legend->reparent(this, QPoint(0, 0));
827 #else
828                     d_data->legend->setParent(this);
829 #endif
830                 }
831             }
832 
833             const QwtPlotItemList& itmList = itemList();
834             for ( QwtPlotItemIterator it = itmList.begin();
835                 it != itmList.end(); ++it )
836             {
837                 (*it)->updateLegend(d_data->legend);
838             }
839 
840             QLayout *l = d_data->legend->contentsWidget()->layout();
841             if ( l && l->inherits("QwtDynGridLayout") )
842             {
843                 QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
844                 switch(d_data->layout->legendPosition())
845                 {
846                     case LeftLegend:
847                     case RightLegend:
848                         tl->setMaxCols(1); // 1 column: align vertical
849                         break;
850                     case TopLegend:
851                     case BottomLegend:
852                         tl->setMaxCols(0); // unlimited
853                         break;
854                     case ExternalLegend:
855                         break;
856                 }
857             }
858         }
859         updateTabOrder();
860     }
861 
862     updateLayout();
863 }
864