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 
00238 QwtLegend::QwtLegend(QWidget *parent): 
00239     QFrame(parent)
00240 {
00241     setFrameStyle(NoFrame);
00242 
00243     d_data = new QwtLegend::PrivateData;
00244     d_data->itemMode = QwtLegend::ReadOnlyItem;
00245     d_data->displayPolicy = QwtLegend::Auto;
00246     d_data->identifierMode = QwtLegendItem::ShowLine | 
00247         QwtLegendItem::ShowSymbol | QwtLegendItem::ShowText;
00248 
00249     d_data->view = new QwtLegend::PrivateData::LegendView(this);
00250     d_data->view->setFrameStyle(NoFrame);
00251 
00252     QwtDynGridLayout *layout = new QwtDynGridLayout(
00253         d_data->view->contentsWidget);
00254 #if QT_VERSION < 0x040000
00255     layout->setAutoAdd(true);
00256 #endif
00257     layout->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
00258 
00259     d_data->view->contentsWidget->installEventFilter(this);
00260 }
00261 
00262 QwtLegend::~QwtLegend()
00263 {
00264     delete d_data;
00265 }
00266 
00275 void QwtLegend::setDisplayPolicy(LegendDisplayPolicy policy, int mode)
00276 {
00277     d_data->displayPolicy = policy;
00278     if (-1 != mode)
00279        d_data->identifierMode = mode;
00280 
00281     QMap<QWidget *, const QwtPlotItem *> &map = 
00282         d_data->map.widgetMap();
00283 
00284     QMap<QWidget *, const QwtPlotItem *>::iterator it;
00285     for ( it = map.begin(); it != map.end(); ++it ) 
00286     {
00287 #if QT_VERSION < 0x040000
00288         QwtPlotItem *item = (QwtPlotItem *)it.data();
00289 #else
00290         QwtPlotItem *item = (QwtPlotItem *)it.value();
00291 #endif
00292         if ( item )
00293             item->updateLegend(this);
00294     }
00295 }
00296 
00303 QwtLegend::LegendDisplayPolicy QwtLegend::displayPolicy() const 
00304 { 
00305     return d_data->displayPolicy; 
00306 }
00307 
00308 void QwtLegend::setItemMode(LegendItemMode mode)
00309 {
00310     d_data->itemMode = mode;
00311 }
00312 
00313 QwtLegend::LegendItemMode QwtLegend::itemMode() const
00314 {
00315     return d_data->itemMode;
00316 }
00317 
00325 int QwtLegend::identifierMode() const
00326 {
00327     return d_data->identifierMode;
00328 }
00329 
00334 QWidget *QwtLegend::contentsWidget() 
00335 { 
00336     return d_data->view->contentsWidget; 
00337 }
00338 
00339 QScrollBar *QwtLegend::horizontalScrollBar() const
00340 {
00341     return d_data->view->horizontalScrollBar();
00342 }
00343 
00344 QScrollBar *QwtLegend::verticalScrollBar() const
00345 {
00346     return d_data->view->horizontalScrollBar();
00347 }
00348 
00354 const QWidget *QwtLegend::contentsWidget() const 
00355 { 
00356     return d_data->view->contentsWidget; 
00357 }
00358 
00366 void QwtLegend::insert(const QwtPlotItem *plotItem, QWidget *legendItem)
00367 {
00368     if ( legendItem == NULL || plotItem == NULL )
00369         return;
00370 
00371     QWidget *contentsWidget = d_data->view->contentsWidget;
00372 
00373     if ( legendItem->parent() != contentsWidget )
00374     {
00375 #if QT_VERSION >= 0x040000
00376         legendItem->setParent(contentsWidget);
00377 #else
00378         legendItem->reparent(contentsWidget, QPoint(0, 0));
00379 #endif
00380     }
00381 
00382     legendItem->show();
00383 
00384     d_data->map.insert(plotItem, legendItem);
00385 
00386     layoutContents();
00387 
00388     if ( contentsWidget->layout() )
00389     {
00390 #if QT_VERSION >= 0x040000
00391         contentsWidget->layout()->addWidget(legendItem);
00392 #endif
00393 
00394         // set tab focus chain
00395 
00396         QWidget *w = NULL;
00397 
00398 #if QT_VERSION < 0x040000
00399         QLayoutIterator layoutIterator = 
00400             contentsWidget->layout()->iterator();
00401         for ( QLayoutItem *item = layoutIterator.current();
00402             item != 0; item = ++layoutIterator)
00403         {
00404 #else
00405         for (int i = 0; i < contentsWidget->layout()->count(); i++)
00406         {
00407             QLayoutItem *item = contentsWidget->layout()->itemAt(i);
00408 #endif
00409             if ( w && item->widget() )
00410             {
00411                 QWidget::setTabOrder(w, item->widget());
00412                 w = item->widget();
00413             }
00414         }
00415     }
00416 }
00417 
00418 QWidget *QwtLegend::find(const QwtPlotItem *plotItem) const
00419 {
00420     return d_data->map.find(plotItem);
00421 }
00422 
00423 QwtPlotItem *QwtLegend::find(const QWidget *legendItem) const
00424 {
00425     return d_data->map.find(legendItem);
00426 }
00427 
00429 void QwtLegend::remove(const QwtPlotItem *plotItem)
00430 { 
00431     QWidget *legendItem = d_data->map.find(plotItem);
00432     d_data->map.remove(legendItem); 
00433     delete legendItem;
00434 }
00435 
00437 void QwtLegend::clear()
00438 {
00439 #if QT_VERSION < 0x040000
00440     bool doUpdate = isUpdatesEnabled();
00441 #else
00442     bool doUpdate = updatesEnabled();
00443 #endif
00444     setUpdatesEnabled(false);
00445 
00446     d_data->map.clear();
00447 
00448     setUpdatesEnabled(doUpdate);
00449     update();
00450 }
00451 
00453 QSize QwtLegend::sizeHint() const
00454 {
00455     QSize hint = d_data->view->contentsWidget->sizeHint();
00456     hint += QSize(2 * frameWidth(), 2 * frameWidth());
00457 
00458     return hint;
00459 }
00460 
00464 int QwtLegend::heightForWidth(int w) const
00465 {
00466     w -= 2 * frameWidth();
00467 
00468     int h = d_data->view->contentsWidget->heightForWidth(w);
00469 #if QT_VERSION < 0x040000
00470 
00471     // Asking the layout is the default implementation in Qt4 
00472 
00473     if ( h <= 0 ) 
00474     {
00475         QLayout *l = d_data->view->contentsWidget->layout();
00476         if ( l && l->hasHeightForWidth() )
00477             h = l->heightForWidth(w);
00478     }
00479 #endif
00480     if ( h >= 0 )
00481         h += 2 * frameWidth();
00482 
00483     return h;
00484 }
00485 
00489 void QwtLegend::layoutContents()
00490 {
00491     const QSize visibleSize = d_data->view->viewport()->size();
00492 
00493     const QLayout *l = d_data->view->contentsWidget->layout();
00494     if ( l && l->inherits("QwtDynGridLayout") )
00495     {
00496         const QwtDynGridLayout *tl = (const QwtDynGridLayout *)l;
00497 
00498         const int minW = int(tl->maxItemWidth()) + 2 * tl->margin();
00499 
00500         int w = qwtMax(visibleSize.width(), minW);
00501         int h = qwtMax(tl->heightForWidth(w), visibleSize.height());
00502 
00503         const int vpWidth = d_data->view->viewportSize(w, h).width();
00504         if ( w > vpWidth )
00505         {
00506             w = qwtMax(vpWidth, minW);
00507             h = qwtMax(tl->heightForWidth(w), visibleSize.height());
00508         }
00509 
00510         d_data->view->contentsWidget->resize(w, h);
00511 #if QT_VERSION < 0x040000
00512         d_data->view->resizeContents(w, h);
00513 #endif
00514     }
00515 }
00516 
00517 /*
00518   Filter layout related events of QwtLegend::contentsWidget().
00519 */
00520 
00521 bool QwtLegend::eventFilter(QObject *o, QEvent *e)
00522 {
00523     if ( o == d_data->view->contentsWidget )
00524     {
00525         switch(e->type())
00526         {
00527             case QEvent::ChildRemoved:
00528             {   
00529                 const QChildEvent *ce = (const QChildEvent *)e;
00530                 if ( ce->child()->isWidgetType() )
00531                     d_data->map.remove((QWidget *)ce->child());
00532                 break;
00533             }
00534 #if QT_VERSION < 0x040000
00535             case QEvent::LayoutHint:
00536 #else
00537             case QEvent::LayoutRequest:
00538 #endif
00539             {
00540                 layoutContents();
00541                 break;
00542             }
00543             default:
00544                 break;
00545         }
00546     }
00547     
00548     return QFrame::eventFilter(o, e);
00549 }
00550 
00551 
00553 bool QwtLegend::isEmpty() const
00554 {
00555     return d_data->map.count() == 0;
00556 }
00557 
00559 uint QwtLegend::itemCount() const
00560 {
00561     return d_data->map.count();
00562 }
00563 
00564 #if QT_VERSION < 0x040000
00565 QValueList<QWidget *> QwtLegend::legendItems() const
00566 #else
00567 QList<QWidget *> QwtLegend::legendItems() const
00568 #endif
00569 {
00570     const QMap<QWidget *, const QwtPlotItem *> &map = 
00571         d_data->map.widgetMap();
00572 
00573 #if QT_VERSION < 0x040000
00574     QValueList<QWidget *> list;
00575 #else
00576     QList<QWidget *> list;
00577 #endif
00578 
00579     QMap<QWidget *, const QwtPlotItem *>::const_iterator it;
00580     for ( it = map.begin(); it != map.end(); ++it ) 
00581         list += it.key();
00582 
00583     return list;
00584 }
00585 
00586 void QwtLegend::resizeEvent(QResizeEvent *e)
00587 {
00588     QFrame::resizeEvent(e);
00589     d_data->view->setGeometry(contentsRect());
00590 }

Generated on Wed Aug 31 23:02:29 2005 for Qwt User's Guide by  doxygen 1.4.1