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

Last change on this file since 5518 was 4271, checked in by mervart, 12 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.