source: ntrip/trunk/BNC/qwt/qwt_legend.cpp @ 4271

Last change on this file since 4271 was 4271, checked in by mervart, 7 years ago
File size: 12.6 KB
Line 
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 "qwt_legend.h"
11#include "qwt_legend_itemmanager.h"
12#include "qwt_legend_item.h"
13#include "qwt_dyngrid_layout.h"
14#include "qwt_math.h"
15#include <qapplication.h>
16#include <qmap.h>
17#include <qscrollbar.h>
18#include <qscrollarea.h>
19
20class QwtLegend::PrivateData
21{
22public:
23    class LegendMap
24    {
25    public:
26        void insert( const QwtLegendItemManager *, QWidget * );
27
28        void remove( const QwtLegendItemManager * );
29        void remove( QWidget * );
30
31        void clear();
32
33        uint count() const;
34
35        inline const QWidget *find( const QwtLegendItemManager * ) const;
36        inline QWidget *find( const QwtLegendItemManager * );
37
38        inline const QwtLegendItemManager *find( const QWidget * ) const;
39        inline QwtLegendItemManager *find( const QWidget * );
40
41        const QMap<QWidget *, const QwtLegendItemManager *> &widgetMap() const;
42        QMap<QWidget *, const QwtLegendItemManager *> &widgetMap();
43
44    private:
45        QMap<QWidget *, const QwtLegendItemManager *> d_widgetMap;
46        QMap<const QwtLegendItemManager *, QWidget *> d_itemMap;
47    };
48
49    QwtLegend::LegendItemMode itemMode;
50
51    LegendMap map;
52
53    class LegendView;
54    LegendView *view;
55};
56
57class QwtLegend::PrivateData::LegendView: public QScrollArea
58{
59public:
60    LegendView( QWidget *parent ):
61        QScrollArea( parent )
62    {
63        setFocusPolicy( Qt::NoFocus );
64
65        contentsWidget = new QWidget( this );
66        contentsWidget->setObjectName( "QwtLegendViewContents" );
67
68        setWidget( contentsWidget );
69        setWidgetResizable( false );
70
71        viewport()->setObjectName( "QwtLegendViewport" );
72
73        // QScrollArea::setWidget internally sets autoFillBackground to true
74        // But we don't want a background.
75        contentsWidget->setAutoFillBackground( false );
76        viewport()->setAutoFillBackground( false );
77    }
78
79    virtual bool viewportEvent( QEvent *e )
80    {
81        bool ok = QScrollArea::viewportEvent( e );
82
83        if ( e->type() == QEvent::Resize )
84        {
85            QEvent event( QEvent::LayoutRequest );
86            QApplication::sendEvent( contentsWidget, &event );
87        }
88        return ok;
89    }
90
91    QSize viewportSize( int w, int h ) const
92    {
93        const int sbHeight = horizontalScrollBar()->sizeHint().height();
94        const int sbWidth = verticalScrollBar()->sizeHint().width();
95
96        const int cw = contentsRect().width();
97        const int ch = contentsRect().height();
98
99        int vw = cw;
100        int vh = ch;
101
102        if ( w > vw )
103            vh -= sbHeight;
104
105        if ( h > vh )
106        {
107            vw -= sbWidth;
108            if ( w > vw && vh == ch )
109                vh -= sbHeight;
110        }
111        return QSize( vw, vh );
112    }
113
114    QWidget *contentsWidget;
115};
116
117void QwtLegend::PrivateData::LegendMap::insert(
118    const QwtLegendItemManager *item, QWidget *widget )
119{
120    d_itemMap.insert( item, widget );
121    d_widgetMap.insert( widget, item );
122}
123
124void QwtLegend::PrivateData::LegendMap::remove( const QwtLegendItemManager *item )
125{
126    QWidget *widget = d_itemMap[item];
127    d_itemMap.remove( item );
128    d_widgetMap.remove( widget );
129}
130
131void QwtLegend::PrivateData::LegendMap::remove( QWidget *widget )
132{
133    const QwtLegendItemManager *item = d_widgetMap[widget];
134    d_itemMap.remove( item );
135    d_widgetMap.remove( widget );
136}
137
138void QwtLegend::PrivateData::LegendMap::clear()
139{
140
141    /*
142       We can't delete the widgets in the following loop, because
143       we would get ChildRemoved events, changing d_itemMap, while
144       we are iterating.
145     */
146
147    QList<const QWidget *> widgets;
148
149    QMap<const QwtLegendItemManager *, QWidget *>::const_iterator it;
150    for ( it = d_itemMap.begin(); it != d_itemMap.end(); ++it )
151        widgets.append( it.value() );
152
153    d_itemMap.clear();
154    d_widgetMap.clear();
155
156    for ( int i = 0; i < widgets.size(); i++ )
157        delete widgets[i];
158}
159
160uint QwtLegend::PrivateData::LegendMap::count() const
161{
162    return d_itemMap.count();
163}
164
165inline const QWidget *QwtLegend::PrivateData::LegendMap::find( 
166    const QwtLegendItemManager *item ) const
167{
168    if ( !d_itemMap.contains( item ) )
169        return NULL;
170
171    return d_itemMap[item];
172}
173
174inline QWidget *QwtLegend::PrivateData::LegendMap::find( 
175    const QwtLegendItemManager *item )
176{
177    if ( !d_itemMap.contains( item ) )
178        return NULL;
179
180    return d_itemMap[item];
181}
182
183inline const QwtLegendItemManager *QwtLegend::PrivateData::LegendMap::find(
184    const QWidget *widget ) const
185{
186    QWidget *w = const_cast<QWidget *>( widget );
187    if ( !d_widgetMap.contains( w ) )
188        return NULL;
189
190    return d_widgetMap[w];
191}
192
193inline QwtLegendItemManager *QwtLegend::PrivateData::LegendMap::find(
194    const QWidget *widget )
195{
196    QWidget *w = const_cast<QWidget *>( widget );
197    if ( !d_widgetMap.contains( w ) )
198        return NULL;
199
200    return const_cast<QwtLegendItemManager *>( d_widgetMap[w] );
201}
202
203inline const QMap<QWidget *, const QwtLegendItemManager *> &
204QwtLegend::PrivateData::LegendMap::widgetMap() const
205{
206    return d_widgetMap;
207}
208
209inline QMap<QWidget *, const QwtLegendItemManager *> &
210QwtLegend::PrivateData::LegendMap::widgetMap()
211{
212    return d_widgetMap;
213}
214
215/*!
216  Constructor
217
218  \param parent Parent widget
219*/
220QwtLegend::QwtLegend( QWidget *parent ):
221    QFrame( parent )
222{
223    setFrameStyle( NoFrame );
224
225    d_data = new QwtLegend::PrivateData;
226    d_data->itemMode = QwtLegend::ReadOnlyItem;
227
228    d_data->view = new QwtLegend::PrivateData::LegendView( this );
229    d_data->view->setObjectName( "QwtLegendView" );
230    d_data->view->setFrameStyle( NoFrame );
231
232    QwtDynGridLayout *gridLayout = new QwtDynGridLayout(
233        d_data->view->contentsWidget );
234    gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop );
235
236    d_data->view->contentsWidget->installEventFilter( this );
237
238    QVBoxLayout *layout = new QVBoxLayout( this );
239    layout->setContentsMargins( 0, 0, 0, 0 );
240    layout->addWidget( d_data->view );
241}
242
243//! Destructor
244QwtLegend::~QwtLegend()
245{
246    delete d_data;
247}
248
249//! \sa LegendItemMode
250void QwtLegend::setItemMode( LegendItemMode mode )
251{
252    d_data->itemMode = mode;
253}
254
255//! \sa LegendItemMode
256QwtLegend::LegendItemMode QwtLegend::itemMode() const
257{
258    return d_data->itemMode;
259}
260
261/*!
262  The contents widget is the only child of the viewport of
263  the internal QScrollArea  and the parent widget of all legend items.
264
265  \return Container widget of the legend items
266*/
267QWidget *QwtLegend::contentsWidget()
268{
269    return d_data->view->contentsWidget;
270}
271
272/*!
273  \return Horizontal scrollbar
274  \sa verticalScrollBar()
275*/
276QScrollBar *QwtLegend::horizontalScrollBar() const
277{
278    return d_data->view->horizontalScrollBar();
279}
280
281/*!
282  \return Vertical scrollbar
283  \sa horizontalScrollBar()
284*/
285QScrollBar *QwtLegend::verticalScrollBar() const
286{
287    return d_data->view->verticalScrollBar();
288}
289
290/*!
291  The contents widget is the only child of the viewport of
292  the internal QScrollArea  and the parent widget of all legend items.
293
294  \return Container widget of the legend items
295
296*/
297const QWidget *QwtLegend::contentsWidget() const
298{
299    return d_data->view->contentsWidget;
300}
301
302/*!
303  Insert a new item for a plot item
304  \param plotItem Plot item
305  \param legendItem New legend item
306  \note The parent of item will be changed to contentsWidget()
307*/
308void QwtLegend::insert( const QwtLegendItemManager *plotItem, QWidget *legendItem )
309{
310    if ( legendItem == NULL || plotItem == NULL )
311        return;
312
313    QWidget *contentsWidget = d_data->view->contentsWidget;
314
315    if ( legendItem->parent() != contentsWidget )
316        legendItem->setParent( contentsWidget );
317
318    legendItem->show();
319
320    d_data->map.insert( plotItem, legendItem );
321
322    layoutContents();
323
324    if ( contentsWidget->layout() )
325    {
326        contentsWidget->layout()->addWidget( legendItem );
327
328        // set tab focus chain
329
330        QWidget *w = NULL;
331
332        for ( int i = 0; i < contentsWidget->layout()->count(); i++ )
333        {
334            QLayoutItem *item = contentsWidget->layout()->itemAt( i );
335            if ( w && item->widget() )
336                QWidget::setTabOrder( w, item->widget() );
337
338            w = item->widget();
339        }
340    }
341    if ( parentWidget() && parentWidget()->layout() == NULL )
342    {
343        /*
344           updateGeometry() doesn't post LayoutRequest in certain
345           situations, like when we are hidden. But we want the
346           parent widget notified, so it can show/hide the legend
347           depending on its items.
348         */
349        QApplication::postEvent( parentWidget(),
350            new QEvent( QEvent::LayoutRequest ) );
351    }
352}
353
354/*!
355  Find the widget that represents a plot item
356
357  \param plotItem Plot item
358  \return Widget on the legend, or NULL
359*/
360QWidget *QwtLegend::find( const QwtLegendItemManager *plotItem ) const
361{
362    return d_data->map.find( plotItem );
363}
364
365/*!
366  Find the widget that represents a plot item
367
368  \param legendItem Legend item
369  \return Widget on the legend, or NULL
370*/
371QwtLegendItemManager *QwtLegend::find( const QWidget *legendItem ) const
372{
373    return d_data->map.find( legendItem );
374}
375
376/*!
377   Find the corresponding item for a plotItem and remove it
378   from the item list.
379
380   \param plotItem Plot item
381*/
382void QwtLegend::remove( const QwtLegendItemManager *plotItem )
383{
384    QWidget *legendItem = d_data->map.find( plotItem );
385    d_data->map.remove( legendItem );
386    delete legendItem;
387}
388
389//! Remove all items.
390void QwtLegend::clear()
391{
392    bool doUpdate = updatesEnabled();
393    if ( doUpdate )
394        setUpdatesEnabled( false );
395
396    d_data->map.clear();
397
398    if ( doUpdate )
399        setUpdatesEnabled( true );
400
401    update();
402}
403
404//! Return a size hint.
405QSize QwtLegend::sizeHint() const
406{
407    QSize hint = d_data->view->contentsWidget->sizeHint();
408    hint += QSize( 2 * frameWidth(), 2 * frameWidth() );
409
410    return hint;
411}
412
413/*!
414  \return The preferred height, for the width w.
415  \param width Width
416*/
417int QwtLegend::heightForWidth( int width ) const
418{
419    width -= 2 * frameWidth();
420
421    int h = d_data->view->contentsWidget->heightForWidth( width );
422    if ( h >= 0 )
423        h += 2 * frameWidth();
424
425    return h;
426}
427
428/*!
429  Adjust contents widget and item layout to the size of the viewport().
430*/
431void QwtLegend::layoutContents()
432{
433    const QSize visibleSize = 
434        d_data->view->viewport()->contentsRect().size();
435
436    const QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
437        d_data->view->contentsWidget->layout() );
438    if ( tl )
439    {
440        const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin();
441
442        int w = qMax( visibleSize.width(), minW );
443        int h = qMax( tl->heightForWidth( w ), visibleSize.height() );
444
445        const int vpWidth = d_data->view->viewportSize( w, h ).width();
446        if ( w > vpWidth )
447        {
448            w = qMax( vpWidth, minW );
449            h = qMax( tl->heightForWidth( w ), visibleSize.height() );
450        }
451
452        d_data->view->contentsWidget->resize( w, h );
453    }
454}
455
456/*!
457  Handle QEvent::ChildRemoved andQEvent::LayoutRequest events
458  for the contentsWidget().
459
460  \param object Object to be filtered
461  \param event Event
462*/
463bool QwtLegend::eventFilter( QObject *object, QEvent *event )
464{
465    if ( object == d_data->view->contentsWidget )
466    {
467        switch ( event->type() )
468        {
469            case QEvent::ChildRemoved:
470            {
471                const QChildEvent *ce = 
472                    static_cast<const QChildEvent *>(event);
473                if ( ce->child()->isWidgetType() )
474                {
475                    QWidget *w = static_cast< QWidget * >( ce->child() );
476                    d_data->map.remove( w );
477                }
478                break;
479            }
480            case QEvent::LayoutRequest:
481            {
482                layoutContents();
483                break;
484            }
485            default:
486                break;
487        }
488    }
489
490    return QFrame::eventFilter( object, event );
491}
492
493
494//! Return true, if there are no legend items.
495bool QwtLegend::isEmpty() const
496{
497    return d_data->map.count() == 0;
498}
499
500//! Return the number of legend items.
501uint QwtLegend::itemCount() const
502{
503    return d_data->map.count();
504}
505
506//! Return a list of all legend items
507QList<QWidget *> QwtLegend::legendItems() const
508{
509    const QMap<QWidget *, const QwtLegendItemManager *> &map =
510        d_data->map.widgetMap();
511
512    QList<QWidget *> list;
513
514    QMap<QWidget *, const QwtLegendItemManager *>::const_iterator it;
515    for ( it = map.begin(); it != map.end(); ++it )
516        list += it.key();
517
518    return list;
519}
Note: See TracBrowser for help on using the repository browser.