00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #include <qpainter.h>
00011 #if QT_VERSION < 0x040000
00012 #include <qguardedptr.h>
00013 #include <qfocusdata.h>
00014 #else
00015 #include <qpointer.h>
00016 #include <qpaintengine.h>
00017 #endif
00018 #include <qapplication.h>
00019 #include <qevent.h>
00020 #include "qwt_plot.h"
00021 #include "qwt_plot_dict.h"
00022 #include "qwt_plot_layout.h"
00023 #include "qwt_rect.h"
00024 #include "qwt_scale_widget.h"
00025 #include "qwt_scale_engine.h"
00026 #include "qwt_text_label.h"
00027 #include "qwt_legend.h"
00028 #include "qwt_dyngrid_layout.h"
00029 #include "qwt_plot_canvas.h"
00030 #include "qwt_paint_buffer.h"
00031 
00032 class QwtPlot::PrivateData
00033 {
00034 public:
00035 #if QT_VERSION < 0x040000
00036     QGuardedPtr<QwtTextLabel> lblTitle;
00037     QGuardedPtr<QwtPlotCanvas> canvas;
00038     QGuardedPtr<QwtLegend> legend;
00039 #else
00040     QPointer<QwtTextLabel> lblTitle;
00041     QPointer<QwtPlotCanvas> canvas;
00042     QPointer<QwtLegend> legend;
00043 #endif
00044     QwtPlotLayout *layout;
00045 
00046     bool autoReplot;
00047 };
00048 
00053 QwtPlot::QwtPlot(QWidget *parent):
00054     QFrame(parent)
00055 {
00056     initPlot(QwtText());
00057 }
00058 
00064 QwtPlot::QwtPlot(const QwtText &title, QWidget *parent):
00065     QFrame(parent)
00066 {
00067     initPlot(title);
00068 }
00069 
00070 #if QT_VERSION < 0x040000
00071 
00076 QwtPlot::QwtPlot(QWidget *parent, const char *name):
00077     QFrame(parent, name)
00078 {   
00079     initPlot(QwtText());
00080 }   
00081 #endif
00082 
00083 
00085 QwtPlot::~QwtPlot()
00086 {
00087     detachItems(QwtPlotItem::Rtti_PlotItem, autoDelete());
00088 
00089     delete d_data->layout;
00090     deleteAxesData();
00091     delete d_data;
00092 }
00093 
00098 void QwtPlot::initPlot(const QwtText &title)
00099 {
00100     d_data = new PrivateData;
00101 
00102 #if QT_VERSION < 0x040000
00103     setWFlags(Qt::WNoAutoErase);
00104 #endif 
00105 
00106     d_data->layout = new QwtPlotLayout;
00107 
00108     d_data->autoReplot = false;
00109 
00110     d_data->lblTitle = new QwtTextLabel(title, this);
00111     d_data->lblTitle->setFont(QFont(fontInfo().family(), 14, QFont::Bold));
00112 
00113     QwtText text(title);
00114     int flags = Qt::AlignCenter;
00115 #if QT_VERSION < 0x040000
00116     flags |= Qt::WordBreak | Qt::ExpandTabs;
00117 #else
00118     flags |= Qt::TextWordWrap;
00119 #endif
00120     text.setRenderFlags(flags);
00121     d_data->lblTitle->setText(text);
00122 
00123     d_data->legend = NULL;
00124 
00125     initAxesData();
00126 
00127     d_data->canvas = new QwtPlotCanvas(this);
00128     d_data->canvas->setFrameStyle(QFrame::Panel|QFrame::Sunken);
00129     d_data->canvas->setLineWidth(2);
00130     d_data->canvas->setMidLineWidth(0);
00131 
00132     updateTabOrder();
00133 
00134     setSizePolicy(QSizePolicy::MinimumExpanding, 
00135         QSizePolicy::MinimumExpanding);
00136 }
00137 
00141 bool QwtPlot::event(QEvent *e)
00142 {
00143     bool ok = QFrame::event(e);
00144     switch(e->type())
00145     {
00146 #if QT_VERSION < 0x040000
00147         case QEvent::LayoutHint:
00148 #else
00149         case QEvent::LayoutRequest:
00150 #endif
00151             updateLayout();
00152             break;
00153 #if QT_VERSION >= 0x040000
00154         case QEvent::PolishRequest:
00155             polish();
00156             break;
00157 #endif
00158         default:;
00159     }
00160     return ok;
00161 }
00162 
00167 void QwtPlot::autoRefresh()
00168 {
00169     if (d_data->autoReplot)
00170         replot();
00171 }
00172 
00187 void QwtPlot::setAutoReplot(bool tf)
00188 {
00189     d_data->autoReplot = tf;
00190 }
00191 
00195 bool QwtPlot::autoReplot() const
00196 {
00197     return d_data->autoReplot; 
00198 }
00199 
00204 void QwtPlot::setTitle(const QString &t)
00205 {
00206     if ( t != d_data->lblTitle->text().text() )
00207     {
00208         d_data->lblTitle->setText(t);
00209         updateLayout();
00210     }
00211 }
00212 
00217 void QwtPlot::setTitle(const QwtText &t)
00218 {
00219     if ( t != d_data->lblTitle->text() )
00220     {
00221         d_data->lblTitle->setText(t);
00222         updateLayout();
00223     }
00224 }
00225 
00230 QwtText QwtPlot::title() const
00231 {
00232     return d_data->lblTitle->text();
00233 }
00234 
00238 QwtPlotLayout *QwtPlot::plotLayout()
00239 {
00240     return d_data->layout;
00241 }
00242 
00246 const QwtPlotLayout *QwtPlot::plotLayout() const
00247 {
00248     return d_data->layout;
00249 }
00250 
00254 QwtTextLabel *QwtPlot::titleLabel()
00255 {
00256     return d_data->lblTitle;
00257 }
00258 
00262 const QwtTextLabel *QwtPlot::titleLabel() const
00263 {
00264     return d_data->lblTitle;
00265 }
00266 
00271 QwtLegend *QwtPlot::legend()
00272 { 
00273     return d_data->legend;
00274 }   
00275 
00280 const QwtLegend *QwtPlot::legend() const
00281 { 
00282     return d_data->legend;
00283 }   
00284 
00285 
00289 QwtPlotCanvas *QwtPlot::canvas()
00290 { 
00291     return d_data->canvas;
00292 }   
00293 
00297 const QwtPlotCanvas *QwtPlot::canvas() const
00298 { 
00299     return d_data->canvas;
00300 }
00301 
00302 void QwtPlot::polish()
00303 {
00304     replot();
00305 
00306 #if QT_VERSION < 0x040000
00307     QFrame::polish();
00308 #endif
00309 }
00310 
00316 QSize QwtPlot::sizeHint() const
00317 {
00318     int dw = 0;
00319     int dh = 0;
00320     for ( int axisId = 0; axisId < axisCnt; axisId++ )
00321     {
00322         if ( axisEnabled(axisId) )
00323         {   
00324             const int niceDist = 40;
00325             const QwtScaleWidget *scaleWidget = axisWidget(axisId);
00326             const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv();
00327             const int majCnt = scaleDiv.ticks(QwtScaleDiv::MajorTick).count();
00328 
00329             if ( axisId == yLeft || axisId == yRight )
00330             {
00331                 int hDiff = (majCnt - 1) * niceDist 
00332                     - scaleWidget->minimumSizeHint().height();
00333                 if ( hDiff > dh )
00334                     dh = hDiff;
00335             }
00336             else
00337             {
00338                 int wDiff = (majCnt - 1) * niceDist 
00339                     - scaleWidget->minimumSizeHint().width();
00340                 if ( wDiff > dw )
00341                     dw = wDiff;
00342             }
00343         }
00344     }
00345     return minimumSizeHint() + QSize(dw, dh);
00346 }
00347 
00351 QSize QwtPlot::minimumSizeHint() const
00352 {
00353     QSize hint = d_data->layout->minimumSizeHint(this);
00354     hint += QSize(2 * frameWidth(), 2 * frameWidth());
00355 
00356     return hint;
00357 }
00358 
00360 void QwtPlot::resizeEvent(QResizeEvent *e)
00361 {
00362     QFrame::resizeEvent(e);
00363     updateLayout();
00364 }
00365 
00376 void QwtPlot::replot()
00377 {
00378     bool doAutoReplot = autoReplot();
00379     setAutoReplot(false);
00380 
00381     updateAxes();
00382 
00383     
00384 
00385 
00386 
00387 
00388 #if QT_VERSION >= 0x040000
00389     QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
00390 #else
00391     QApplication::sendPostedEvents(this, QEvent::LayoutHint);
00392 #endif
00393 
00394     QwtPlotCanvas &canvas = *d_data->canvas;
00395 
00396     canvas.invalidatePaintCache();
00397 
00398     
00399 
00400 
00401 
00402     const bool erase = 
00403         !canvas.testPaintAttribute(QwtPlotCanvas::PaintPacked) 
00404         && !canvas.testPaintAttribute(QwtPlotCanvas::PaintCached);
00405 
00406 #if QT_VERSION >= 0x040000
00407     const bool noBackgroundMode = canvas.testAttribute(Qt::WA_NoBackground);
00408     if ( !erase && !noBackgroundMode )
00409         canvas.setAttribute(Qt::WA_NoBackground, true);
00410 
00411     canvas.repaint(canvas.contentsRect());
00412 
00413     if ( !erase && !noBackgroundMode )
00414         canvas.setAttribute(Qt::WA_NoBackground, false);
00415 #else
00416     canvas.repaint(canvas.contentsRect(), erase);
00417 #endif
00418 
00419     setAutoReplot(doAutoReplot);
00420 }
00421 
00426 void QwtPlot::updateLayout()
00427 {
00428     d_data->layout->activate(this, contentsRect());
00429 
00430     
00431     
00432     
00433     if (!d_data->lblTitle->text().isEmpty())
00434     {
00435         d_data->lblTitle->setGeometry(d_data->layout->titleRect());
00436         if (!d_data->lblTitle->isVisible())
00437             d_data->lblTitle->show();
00438     }
00439     else
00440         d_data->lblTitle->hide();
00441 
00442     for (int axisId = 0; axisId < axisCnt; axisId++ )
00443     {
00444         if (axisEnabled(axisId) )
00445         {
00446             axisWidget(axisId)->setGeometry(d_data->layout->scaleRect(axisId));
00447 
00448             if ( axisId == xBottom || axisId == xTop )
00449             {
00450                 QRegion r(d_data->layout->scaleRect(axisId));
00451                 if ( axisEnabled(yLeft) )
00452                     r = r.subtract(QRegion(d_data->layout->scaleRect(yLeft)));
00453                 if ( axisEnabled(yRight) )
00454                     r = r.subtract(QRegion(d_data->layout->scaleRect(yRight)));
00455                 r.translate(-d_data->layout->scaleRect(axisId).x(), 
00456                     -d_data->layout->scaleRect(axisId).y());
00457 
00458                 axisWidget(axisId)->setMask(r);
00459             }
00460             if (!axisWidget(axisId)->isVisible())
00461                 axisWidget(axisId)->show();
00462         }
00463         else
00464             axisWidget(axisId)->hide();
00465     }
00466 
00467     if ( d_data->legend && 
00468         d_data->layout->legendPosition() != ExternalLegend )
00469     {
00470         if (d_data->legend->itemCount() > 0)
00471         {
00472             d_data->legend->setGeometry(d_data->layout->legendRect());
00473             d_data->legend->show();
00474         }
00475         else
00476             d_data->legend->hide();
00477     }
00478 
00479     d_data->canvas->setGeometry(d_data->layout->canvasRect());
00480 }
00481 
00490 void QwtPlot::updateTabOrder()
00491 {
00492 #if QT_VERSION >= 0x040000
00493     using namespace Qt; 
00494 #else
00495     if ( d_data->canvas->focusPolicy() == NoFocus )
00496         return;
00497 #endif
00498     if ( d_data->legend.isNull()  
00499         || d_data->layout->legendPosition() == ExternalLegend
00500         || d_data->legend->legendItems().count() == 0 )
00501     {
00502         return;
00503     }
00504 
00505     
00506     
00507     
00508     
00509 
00510     const bool canvasFirst = 
00511         d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
00512         d_data->layout->legendPosition() == QwtPlot::RightLegend;
00513 
00514     QWidget *previous = NULL; 
00515 
00516     QWidget *w;
00517 #if QT_VERSION >= 0x040000
00518     w = d_data->canvas;
00519     while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
00520 #else
00521     if ( focusData() == NULL )
00522         return;
00523 
00524     while ( focusData()->next() != d_data->canvas );
00525     while ( (w = focusData()->next()) != d_data->canvas )
00526 #endif
00527     {
00528         bool isLegendItem = false;
00529         if ( w->focusPolicy() != NoFocus 
00530             && w->parent() && w->parent() == d_data->legend->contentsWidget() )
00531         {
00532             isLegendItem = true;
00533         }
00534 
00535         if ( canvasFirst )
00536         {
00537             if ( isLegendItem )
00538                 break;
00539 
00540             previous = w;
00541         }
00542         else
00543         {
00544             if ( isLegendItem )
00545                 previous = w;
00546             else
00547             {
00548                 if ( previous )
00549                     break;
00550             }
00551         }
00552     }
00553 
00554     if ( previous && previous != d_data->canvas)
00555         setTabOrder(previous, d_data->canvas);
00556 }
00557 
00568 void QwtPlot::drawCanvas(QPainter *painter)
00569 {
00570     QwtScaleMap maps[axisCnt];
00571     for ( int axisId = 0; axisId < axisCnt; axisId++ )
00572         maps[axisId] = canvasMap(axisId);
00573 
00574     drawItems(painter, 
00575         d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
00576 }
00577 
00586 void QwtPlot::drawItems(QPainter *painter, const QRect &rect, 
00587         const QwtScaleMap map[axisCnt], 
00588         const QwtPlotPrintFilter &pfilter) const
00589 {
00590     const QwtPlotItemList& itmList = itemList();
00591     for ( QwtPlotItemIterator it = itmList.begin();
00592         it != itmList.end(); ++it )
00593     {
00594         QwtPlotItem *item = *it;
00595         if ( item && item->isVisible() )
00596         {
00597             if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
00598                 && item->rtti() == QwtPlotItem::Rtti_PlotGrid )
00599             {
00600                 continue;
00601             }
00602 
00603             painter->save();
00604 
00605 #if QT_VERSION >= 0x040000
00606             painter->setRenderHint(QPainter::Antialiasing,
00607                 item->testRenderHint(QwtPlotItem::RenderAntialiased) );
00608 #endif
00609 
00610             item->draw(painter, 
00611                 map[item->xAxis()], map[item->yAxis()],
00612                 rect);
00613 
00614             painter->restore();
00615         }
00616     }
00617 }
00618 
00626 QwtScaleMap QwtPlot::canvasMap(int axisId) const
00627 {
00628     QwtScaleMap map;
00629     if ( !d_data->canvas )
00630         return map;
00631 
00632     map.setTransformation(axisScaleEngine(axisId)->transformation());
00633 
00634     const QwtScaleDiv *sd = axisScaleDiv(axisId);
00635     map.setScaleInterval(sd->lBound(), sd->hBound());
00636 
00637     if ( axisEnabled(axisId) )
00638     {
00639         const QwtScaleWidget *s = axisWidget(axisId);
00640         if ( axisId == yLeft || axisId == yRight )
00641         {
00642             int y = s->y() + s->startBorderDist() - d_data->canvas->y();
00643             int h = s->height() - s->startBorderDist() - s->endBorderDist();
00644             map.setPaintInterval(y + h - 1, y);
00645         }
00646         else
00647         {
00648             int x = s->x() + s->startBorderDist() - d_data->canvas->x();
00649             int w = s->width() - s->startBorderDist() - s->endBorderDist();
00650             map.setPaintInterval(x, x + w - 1);
00651         }
00652     }
00653     else
00654     {
00655         const int margin = plotLayout()->canvasMargin(axisId);
00656 
00657         const QRect &canvasRect = d_data->canvas->contentsRect();
00658         if ( axisId == yLeft || axisId == yRight )
00659         {
00660             map.setPaintInterval(canvasRect.bottom() - margin, 
00661                 canvasRect.top() + margin);
00662         }
00663         else
00664         {
00665             map.setPaintInterval(canvasRect.left() + margin, 
00666                 canvasRect.right() - margin);
00667         }
00668     }
00669     return map;
00670 }
00671 
00679 void QwtPlot::setMargin(int margin)
00680 {
00681     if ( margin < 0 )
00682         margin = 0;
00683 
00684     if ( margin != d_data->layout->margin() )
00685     {
00686         d_data->layout->setMargin(margin);
00687         updateLayout();
00688     }
00689 }
00690 
00695 int QwtPlot::margin() const
00696 {
00697     return d_data->layout->margin();
00698 }
00699 
00708 void QwtPlot::setCanvasBackground(const QColor &c)
00709 {
00710     QPalette p = d_data->canvas->palette();
00711 
00712     for ( int i = 0; i < QPalette::NColorGroups; i++ )
00713     {
00714 #if QT_VERSION < 0x040000
00715         p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
00716 #else
00717         p.setColor((QPalette::ColorGroup)i, QPalette::Background, c);
00718 #endif
00719     }
00720 
00721     canvas()->setPalette(p);
00722 }
00723 
00730 const QColor & QwtPlot::canvasBackground() const
00731 {
00732 #if QT_VERSION < 0x040000
00733     return canvas()->palette().color(
00734         QPalette::Normal, QColorGroup::Background);
00735 #else
00736     return canvas()->palette().color(
00737         QPalette::Normal, QPalette::Background);
00738 #endif
00739 }
00740 
00747 void QwtPlot::setCanvasLineWidth(int w)
00748 {
00749     canvas()->setLineWidth(w);
00750     updateLayout();
00751 }
00752  
00758 int QwtPlot::canvasLineWidth() const
00759 { 
00760     return canvas()->lineWidth();
00761 }
00762 
00767 bool QwtPlot::axisValid(int axisId)
00768 {
00769     return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
00770 }
00771 
00777 void QwtPlot::legendItemClicked()
00778 {
00779     if ( d_data->legend && sender()->isWidgetType() )
00780     {
00781         QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
00782         if ( plotItem )
00783             emit legendClicked(plotItem);
00784     }
00785 }
00786 
00787 void QwtPlot::legendItemChecked(bool on)
00788 {
00789     if ( d_data->legend && sender()->isWidgetType() )
00790     {
00791         QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
00792         if ( plotItem )
00793             emit legendChecked(plotItem, on);
00794     }
00795 }
00796 
00798 void QwtPlot::clear()
00799 {
00800     detachItems(QwtPlotItem::Rtti_PlotCurve);
00801     detachItems(QwtPlotItem::Rtti_PlotMarker);
00802 }
00803 
00830 void QwtPlot::insertLegend(QwtLegend *legend, 
00831     QwtPlot::LegendPosition pos, double ratio)
00832 {
00833     d_data->layout->setLegendPosition(pos, ratio);
00834 
00835     if ( legend != d_data->legend )
00836     {
00837         if ( d_data->legend && d_data->legend->parent() == this )
00838             delete d_data->legend;
00839 
00840         d_data->legend = legend;
00841 
00842         if ( d_data->legend )
00843         {
00844             if ( pos != ExternalLegend )
00845             {
00846                 if ( d_data->legend->parent() != this )
00847                 {
00848 #if QT_VERSION < 0x040000
00849                     d_data->legend->reparent(this, QPoint(0, 0));
00850 #else
00851                     d_data->legend->setParent(this);
00852 #endif
00853                 }
00854             }
00855 
00856             const QwtPlotItemList& itmList = itemList();
00857             for ( QwtPlotItemIterator it = itmList.begin();
00858                 it != itmList.end(); ++it )
00859             {
00860                 (*it)->updateLegend(d_data->legend);
00861             }
00862 
00863             QLayout *l = d_data->legend->contentsWidget()->layout();
00864             if ( l && l->inherits("QwtDynGridLayout") )
00865             {
00866                 QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
00867                 switch(d_data->layout->legendPosition())
00868                 {
00869                     case LeftLegend:
00870                     case RightLegend:
00871                         tl->setMaxCols(1); 
00872                         break;
00873                     case TopLegend:
00874                     case BottomLegend:
00875                         tl->setMaxCols(0); 
00876                         break;
00877                     case ExternalLegend:
00878                         break;
00879                 }
00880             }
00881         }
00882         updateTabOrder();
00883     }
00884 
00885     updateLayout();
00886 }