Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

qwt_legend.cpp

00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  * 
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 // vim: expandtab
00011 
00012 #include <qapplication.h> 
00013 #include <qmap.h> 
00014 #if QT_VERSION >= 0x040000
00015 #include <qscrollbar.h> 
00016 #endif
00017 #include "qwt_math.h"
00018 #include "qwt_dyngrid_layout.h"
00019 #include "qwt_plot_item.h"
00020 #include "qwt_legend_item.h"
00021 #include "qwt_legend.h"
00022 
00023 class QwtLegend::PrivateData
00024 {
00025 public:
00026     class LegendMap
00027     {
00028     public:
00029         void insert(const QwtPlotItem *, QWidget *);
00030 
00031         void remove(const QwtPlotItem *);
00032         void remove(QWidget *);
00033 
00034         void clear();
00035 
00036         uint count() const;
00037 
00038         inline const QWidget *find(const QwtPlotItem *) const;
00039         inline QWidget *find(const QwtPlotItem *);
00040 
00041         inline const QwtPlotItem *find(const QWidget *) const;
00042         inline QwtPlotItem *find(const QWidget *);
00043 
00044         const QMap<QWidget *, const QwtPlotItem *> &widgetMap() const;
00045         QMap<QWidget *, const QwtPlotItem *> &widgetMap();
00046 
00047     private:
00048         QMap<QWidget *, const QwtPlotItem *> d_widgetMap;
00049         QMap<const QwtPlotItem *, QWidget *> d_itemMap;
00050     };
00051 
00052     QwtLegend::LegendItemMode itemMode;
00053     QwtLegend::LegendDisplayPolicy displayPolicy;
00054     int identifierMode;
00055 
00056     LegendMap map;
00057 
00058     class LegendView;
00059     LegendView *view;
00060 };
00061 
00062 #if QT_VERSION < 0x040000
00063 #include <qscrollview.h>
00064 
00065 class QwtLegend::PrivateData::LegendView: public QScrollView
00066 {
00067 public:
00068     LegendView(QWidget *parent):
00069         QScrollView(parent)
00070     {
00071         setResizePolicy(Manual);
00072 
00073         viewport()->setBackgroundMode(Qt::NoBackground); // Avoid flicker
00074 
00075         contentsWidget = new QWidget(viewport());
00076 
00077         addChild(contentsWidget);
00078     }
00079 
00080     void viewportResizeEvent(QResizeEvent *e)
00081     {
00082         QScrollView::viewportResizeEvent(e);
00083 
00084         // It's not safe to update the layout now, because
00085         // we are in an internal update of the scrollview framework.
00086         // So we delay the update by posting a LayoutHint.
00087 
00088         QApplication::postEvent(contentsWidget, 
00089             new QEvent(QEvent::LayoutHint));
00090     }
00091 
00092     QWidget *contentsWidget;
00093 };
00094 
00095 #else // QT_VERSION >= 0x040000
00096 
00097 #include <qscrollarea.h>
00098 
00099 class QwtLegend::PrivateData::LegendView: public QScrollArea
00100 {
00101 public:
00102     LegendView(QWidget *parent):
00103         QScrollArea(parent)
00104     {
00105         contentsWidget = new QWidget(this);
00106 
00107         setWidget(contentsWidget);
00108         setWidgetResizable(false);
00109     }
00110 
00111     virtual bool viewportEvent(QEvent *e) 
00112     {
00113         bool ok = QScrollArea::viewportEvent(e);
00114 
00115         if ( e->type() == QEvent::Resize )
00116         {
00117             QApplication::postEvent(contentsWidget, 
00118                 new QEvent(QEvent::LayoutRequest));
00119         }
00120         return ok;
00121     }
00122 
00123     QSize viewportSize(int w, int h) const
00124     {
00125         const int sbHeight = horizontalScrollBar()->sizeHint().height();
00126         const int sbWidth = verticalScrollBar()->sizeHint().width();
00127     
00128         const int cw = contentsRect().width();
00129         const int ch = contentsRect().height();
00130 
00131         int vw = cw;
00132         int vh = ch;
00133 
00134         if ( w > vw )
00135             vh -= sbHeight;
00136 
00137         if ( h > vh )
00138         {
00139             vw -= sbWidth;
00140             if ( w > vw && vh == ch )
00141                 vh -= sbHeight;
00142         }
00143         return QSize(vw, vh);
00144     }
00145 
00146     QWidget *contentsWidget;
00147 };
00148 
00149 #endif
00150 
00151 
00152 void QwtLegend::PrivateData::LegendMap::insert(
00153     const QwtPlotItem *item, QWidget *widget)
00154 {
00155     d_itemMap.insert(item, widget);
00156     d_widgetMap.insert(widget, item);
00157 }
00158 
00159 void QwtLegend::PrivateData::LegendMap::remove(const QwtPlotItem *item)
00160 {
00161     QWidget *widget = d_itemMap[item];
00162     d_itemMap.remove(item);
00163     d_widgetMap.remove(widget);
00164 }
00165 
00166 void QwtLegend::PrivateData::LegendMap::remove(QWidget *widget)
00167 {
00168     const QwtPlotItem *item = d_widgetMap[widget];
00169     d_itemMap.remove(item);
00170     d_widgetMap.remove(widget);
00171 }
00172 
00173 void QwtLegend::PrivateData::LegendMap::clear()
00174 {
00175     QMap<QWidget *, const QwtPlotItem *>::const_iterator it;
00176     for ( it = d_widgetMap.begin(); it != d_widgetMap.end(); ++it ) 
00177         delete it.key();
00178 
00179     d_itemMap.clear();
00180     d_widgetMap.clear();
00181 }
00182 
00183 uint QwtLegend::PrivateData::LegendMap::count() const
00184 {
00185     return d_itemMap.count();
00186 }
00187 
00188 inline const QWidget *QwtLegend::PrivateData::LegendMap::find(const QwtPlotItem *item) const
00189 {
00190     if ( !d_itemMap.contains((QwtPlotItem *)item) )
00191         return NULL;
00192 
00193     return d_itemMap[(QwtPlotItem *)item];
00194 }
00195 
00196 inline QWidget *QwtLegend::PrivateData::LegendMap::find(const QwtPlotItem *item)
00197 {
00198     if ( !d_itemMap.contains((QwtPlotItem *)item) )
00199         return NULL;
00200 
00201     return d_itemMap[(QwtPlotItem *)item];
00202 }
00203 
00204 inline const QwtPlotItem *QwtLegend::PrivateData::LegendMap::find(
00205     const QWidget *widget) const
00206 {
00207     if ( !d_widgetMap.contains((QWidget *)widget) )
00208         return NULL;
00209 
00210     return d_widgetMap[(QWidget *)widget];
00211 }
00212 
00213 inline QwtPlotItem *QwtLegend::PrivateData::LegendMap::find(
00214     const QWidget *widget)
00215 {
00216     if ( !d_widgetMap.contains((QWidget *)widget) )
00217         return NULL;
00218 
00219     return (QwtPlotItem *)d_widgetMap[(QWidget *)widget];
00220 }
00221 
00222 inline const QMap<QWidget *, const QwtPlotItem *> &
00223     QwtLegend::PrivateData::LegendMap::widgetMap() const
00224 {
00225     return d_widgetMap;
00226 } 
00227 
00228 inline QMap<QWidget *, const QwtPlotItem *> &
00229     QwtLegend::PrivateData::LegendMap::widgetMap() 
00230 {
00231     return d_widgetMap;
00232 } 
00233 
00237 QwtLegend::QwtLegend(QWidget *parent): 
00238     QFrame(parent)
00239 {
00240     setFrameStyle(NoFrame);
00241 
00242     d_data = new QwtLegend::PrivateData;
00243     d_data->itemMode = QwtLegend::ReadOnlyItem;
00244     d_data->displayPolicy = QwtLegend::Auto;
00245     d_data->identifierMode = QwtLegendItem::ShowLine | 
00246         QwtLegendItem::ShowSymbol | QwtLegendItem::ShowText;
00247 
00248     d_data->view = new QwtLegend::PrivateData::LegendView(this);
00249     d_data->view->setFrameStyle(NoFrame);
00250 
00251     QwtDynGridLayout *layout = new QwtDynGridLayout(
00252         d_data->view->contentsWidget);
00253 #if QT_VERSION < 0x040000
00254     layout->setAutoAdd(true);
00255 #endif
00256     layout->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
00257 
00258     d_data->view->contentsWidget->installEventFilter(this);
00259 }
00260 
00261 QwtLegend::~QwtLegend()
00262 {
00263     delete d_data;
00264 }
00265 
00274 void QwtLegend::setDisplayPolicy(LegendDisplayPolicy policy, int mode)
00275 {
00276     d_data->displayPolicy = policy;
00277     if (-1 != mode)
00278        d_data->identifierMode = mode;
00279 
00280     QMap<QWidget *, const QwtPlotItem *> &map = 
00281         d_data->map.widgetMap();
00282 
00283     QMap<QWidget *, const QwtPlotItem *>::iterator it;
00284     for ( it = map.begin(); it != map.end(); ++it ) 
00285     {
00286 #if QT_VERSION < 0x040000
00287         QwtPlotItem *item = (QwtPlotItem *)it.data();
00288 #else
00289         QwtPlotItem *item = (QwtPlotItem *)it.value();
00290 #endif
00291         if ( item )
00292             item->updateLegend(this);
00293     }
00294 }
00295 
00302 QwtLegend::LegendDisplayPolicy QwtLegend::displayPolicy() const 
00303 { 
00304     return d_data->displayPolicy; 
00305 }
00306 
00307 void QwtLegend::setItemMode(LegendItemMode mode)
00308 {
00309     d_data->itemMode = mode;
00310 }
00311 
00312 QwtLegend::LegendItemMode QwtLegend::itemMode() const
00313 {
00314     return d_data->itemMode;
00315 }
00316 
00324 int QwtLegend::identifierMode() const
00325 {
00326     return d_data->identifierMode;
00327 }
00328 
00333 QWidget *QwtLegend::contentsWidget() 
00334 { 
00335     return d_data->view->contentsWidget; 
00336 }
00337 
00338 QScrollBar *QwtLegend::horizontalScrollBar() const
00339 {
00340     return d_data->view->horizontalScrollBar();
00341 }
00342 
00343 QScrollBar *QwtLegend::verticalScrollBar() const
00344 {
00345     return d_data->view->horizontalScrollBar();
00346 }
00347 
00353 const QWidget *QwtLegend::contentsWidget() const 
00354 { 
00355     return d_data->view->contentsWidget; 
00356 }
00357 
00364 void QwtLegend::insert(const QwtPlotItem *plotItem, QWidget *legendItem)
00365 {
00366     if ( legendItem == NULL || plotItem == NULL )
00367         return;
00368 
00369     QWidget *contentsWidget = d_data->view->contentsWidget;
00370 
00371     if ( legendItem->parent() != contentsWidget )
00372     {
00373 #if QT_VERSION >= 0x040000
00374         legendItem->setParent(contentsWidget);
00375 #else
00376         legendItem->reparent(contentsWidget, QPoint(0, 0));
00377 #endif
00378     }
00379 
00380     legendItem->show();
00381 
00382     d_data->map.insert(plotItem, legendItem);
00383 
00384     layoutContents();
00385 
00386     if ( contentsWidget->layout() )
00387     {
00388 #if QT_VERSION >= 0x040000
00389         contentsWidget->layout()->addWidget(legendItem);
00390 #endif
00391 
00392         // set tab focus chain
00393 
00394         QWidget *w = NULL;
00395 
00396 #if QT_VERSION < 0x040000
00397         QLayoutIterator layoutIterator = 
00398             contentsWidget->layout()->iterator();
00399         for ( QLayoutItem *item = layoutIterator.current();
00400             item != 0; item = ++layoutIterator)
00401         {
00402 #else
00403         for (int i = 0; i < contentsWidget->layout()->count(); i++)
00404         {
00405             QLayoutItem *item = contentsWidget->layout()->itemAt(i);
00406 #endif
00407             if ( w && item->widget() )
00408             {
00409                 QWidget::setTabOrder(w, item->widget());
00410                 w = item->widget();
00411             }
00412         }
00413     }
00414 }
00415 
00416 QWidget *QwtLegend::find(const QwtPlotItem *plotItem) const
00417 {
00418     return d_data->map.find(plotItem);
00419 }
00420 
00421 QwtPlotItem *QwtLegend::find(const QWidget *legendItem) const
00422 {
00423     return d_data->map.find(legendItem);
00424 }
00425 
00427 void QwtLegend::remove(const QwtPlotItem *plotItem)
00428 { 
00429     QWidget *legendItem = d_data->map.find(plotItem);
00430     d_data->map.remove(legendItem); 
00431     delete legendItem;
00432 }
00433 
00435 void QwtLegend::clear()
00436 {
00437 #if QT_VERSION < 0x040000
00438     bool doUpdate = isUpdatesEnabled();
00439 #else
00440     bool doUpdate = updatesEnabled();
00441 #endif
00442     setUpdatesEnabled(false);
00443 
00444     d_data->map.clear();
00445 
00446     setUpdatesEnabled(doUpdate);
00447     update();
00448 }
00449 
00451 QSize QwtLegend::sizeHint() const
00452 {
00453     QSize hint = d_data->view->contentsWidget->sizeHint();
00454     hint += QSize(2 * frameWidth(), 2 * frameWidth());
00455 
00456     return hint;
00457 }
00458 
00462 int QwtLegend::heightForWidth(int w) const
00463 {
00464     w -= 2 * frameWidth();
00465 
00466     int h = d_data->view->contentsWidget->heightForWidth(w);
00467 #if QT_VERSION < 0x040000
00468 
00469     // Asking the layout is the default implementation in Qt4 
00470 
00471     if ( h <= 0 ) 
00472     {
00473         QLayout *l = d_data->view->contentsWidget->layout();
00474         if ( l && l->hasHeightForWidth() )
00475             h = l->heightForWidth(w);
00476     }
00477 #endif
00478     if ( h >= 0 )
00479         h += 2 * frameWidth();
00480 
00481     return h;
00482 }
00483 
00487 void QwtLegend::layoutContents()
00488 {
00489     const QSize visibleSize = d_data->view->viewport()->size();
00490 
00491     const QLayout *l = d_data->view->contentsWidget->layout();
00492     if ( l && l->inherits("QwtDynGridLayout") )
00493     {
00494         const QwtDynGridLayout *tl = (const QwtDynGridLayout *)l;
00495 
00496         const int minW = int(tl->maxItemWidth()) + 2 * tl->margin();
00497 
00498         int w = qwtMax(visibleSize.width(), minW);
00499         int h = qwtMax(tl->heightForWidth(w), visibleSize.height());
00500 
00501         const int vpWidth = d_data->view->viewportSize(w, h).width();
00502         if ( w > vpWidth )
00503         {
00504             w = qwtMax(vpWidth, minW);
00505             h = qwtMax(tl->heightForWidth(w), visibleSize.height());
00506         }
00507 
00508         d_data->view->contentsWidget->resize(w, h);
00509 #if QT_VERSION < 0x040000
00510         d_data->view->resizeContents(w, h);
00511 #endif
00512     }
00513 }
00514 
00515 /*
00516   Filter layout related events of QwtLegend::contentsWidget().
00517 */
00518 
00519 bool QwtLegend::eventFilter(QObject *o, QEvent *e)
00520 {
00521     if ( o == d_data->view->contentsWidget )
00522     {
00523         switch(e->type())
00524         {
00525             case QEvent::ChildRemoved:
00526             {   
00527                 const QChildEvent *ce = (const QChildEvent *)e;
00528                 if ( ce->child()->isWidgetType() )
00529                     d_data->map.remove((QWidget *)ce->child());
00530                 break;
00531             }
00532 #if QT_VERSION < 0x040000
00533             case QEvent::LayoutHint:
00534 #else
00535             case QEvent::LayoutRequest:
00536 #endif
00537             {
00538                 layoutContents();
00539                 break;
00540             }
00541 #if QT_VERSION < 0x040000
00542             case QEvent::Resize:
00543             {
00544                 updateGeometry();
00545                 break;
00546             }
00547 #endif
00548             default:
00549                 break;
00550         }
00551     }
00552     
00553     return QFrame::eventFilter(o, e);
00554 }
00555 
00556 
00558 bool QwtLegend::isEmpty() const
00559 {
00560     return d_data->map.count() == 0;
00561 }
00562 
00564 uint QwtLegend::itemCount() const
00565 {
00566     return d_data->map.count();
00567 }
00568 
00569 #if QT_VERSION < 0x040000
00570 QValueList<QWidget *> QwtLegend::legendItems() const
00571 #else
00572 QList<QWidget *> QwtLegend::legendItems() const
00573 #endif
00574 {
00575     const QMap<QWidget *, const QwtPlotItem *> &map = 
00576         d_data->map.widgetMap();
00577 
00578 #if QT_VERSION < 0x040000
00579     QValueList<QWidget *> list;
00580 #else
00581     QList<QWidget *> list;
00582 #endif
00583 
00584     QMap<QWidget *, const QwtPlotItem *>::const_iterator it;
00585     for ( it = map.begin(); it != map.end(); ++it ) 
00586         list += it.key();
00587 
00588     return list;
00589 }
00590 
00591 void QwtLegend::resizeEvent(QResizeEvent *e)
00592 {
00593     QFrame::resizeEvent(e);
00594     d_data->view->setGeometry(contentsRect());
00595 }

Generated on Mon Jan 30 22:16:25 2006 for Qwt User's Guide by  doxygen 1.4.4