~l3on/ubuntu/oneiric/qwt/fix-921430

« back to all changes in this revision

Viewing changes to qwt-5.0.2/src/qwt_legend.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2007-10-05 15:20:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20071005152041-qmybqh4fj9jejyo2
Tags: 5.0.2-2
* Handle nostrip build option. (Closes: #437877)
* Build libqwt5-doc package in binary-indep target. (Closes: #443110)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
// vim: expandtab
 
11
 
 
12
#include <qapplication.h> 
 
13
#include <qmap.h> 
 
14
#if QT_VERSION >= 0x040000
 
15
#include <qscrollbar.h> 
 
16
#endif
 
17
#include "qwt_math.h"
 
18
#include "qwt_dyngrid_layout.h"
 
19
#include "qwt_plot_item.h"
 
20
#include "qwt_legend_item.h"
 
21
#include "qwt_legend.h"
 
22
 
 
23
class QwtLegend::PrivateData
 
24
{
 
25
public:
 
26
    class LegendMap
 
27
    {
 
28
    public:
 
29
        void insert(const QwtPlotItem *, QWidget *);
 
30
 
 
31
        void remove(const QwtPlotItem *);
 
32
        void remove(QWidget *);
 
33
 
 
34
        void clear();
 
35
 
 
36
        uint count() const;
 
37
 
 
38
        inline const QWidget *find(const QwtPlotItem *) const;
 
39
        inline QWidget *find(const QwtPlotItem *);
 
40
 
 
41
        inline const QwtPlotItem *find(const QWidget *) const;
 
42
        inline QwtPlotItem *find(const QWidget *);
 
43
 
 
44
        const QMap<QWidget *, const QwtPlotItem *> &widgetMap() const;
 
45
        QMap<QWidget *, const QwtPlotItem *> &widgetMap();
 
46
 
 
47
    private:
 
48
        QMap<QWidget *, const QwtPlotItem *> d_widgetMap;
 
49
        QMap<const QwtPlotItem *, QWidget *> d_itemMap;
 
50
    };
 
51
 
 
52
    QwtLegend::LegendItemMode itemMode;
 
53
    QwtLegend::LegendDisplayPolicy displayPolicy;
 
54
    int identifierMode;
 
55
 
 
56
    LegendMap map;
 
57
 
 
58
    class LegendView;
 
59
    LegendView *view;
 
60
};
 
61
 
 
62
#if QT_VERSION < 0x040000
 
63
#include <qscrollview.h>
 
64
 
 
65
class QwtLegend::PrivateData::LegendView: public QScrollView
 
66
{
 
67
public:
 
68
    LegendView(QWidget *parent):
 
69
        QScrollView(parent)
 
70
    {
 
71
        setResizePolicy(Manual);
 
72
 
 
73
        viewport()->setBackgroundMode(Qt::NoBackground); // Avoid flicker
 
74
 
 
75
        contentsWidget = new QWidget(viewport());
 
76
 
 
77
        addChild(contentsWidget);
 
78
    }
 
79
 
 
80
    void viewportResizeEvent(QResizeEvent *e)
 
81
    {
 
82
        QScrollView::viewportResizeEvent(e);
 
83
 
 
84
        // It's not safe to update the layout now, because
 
85
        // we are in an internal update of the scrollview framework.
 
86
        // So we delay the update by posting a LayoutHint.
 
87
 
 
88
        QApplication::postEvent(contentsWidget, 
 
89
            new QEvent(QEvent::LayoutHint));
 
90
    }
 
91
 
 
92
    QWidget *contentsWidget;
 
93
};
 
94
 
 
95
#else // QT_VERSION >= 0x040000
 
96
 
 
97
#include <qscrollarea.h>
 
98
 
 
99
class QwtLegend::PrivateData::LegendView: public QScrollArea
 
100
{
 
101
public:
 
102
    LegendView(QWidget *parent):
 
103
        QScrollArea(parent)
 
104
    {
 
105
        contentsWidget = new QWidget(this);
 
106
 
 
107
        setWidget(contentsWidget);
 
108
        setWidgetResizable(false);
 
109
        setFocusPolicy(Qt::NoFocus);
 
110
    }
 
111
 
 
112
    virtual bool viewportEvent(QEvent *e) 
 
113
    {
 
114
        bool ok = QScrollArea::viewportEvent(e);
 
115
 
 
116
        if ( e->type() == QEvent::Resize )
 
117
        {
 
118
            QEvent event(QEvent::LayoutRequest);
 
119
            QApplication::sendEvent(contentsWidget, &event);
 
120
        }
 
121
        return ok;
 
122
    }
 
123
 
 
124
    QSize viewportSize(int w, int h) const
 
125
    {
 
126
        const int sbHeight = horizontalScrollBar()->sizeHint().height();
 
127
        const int sbWidth = verticalScrollBar()->sizeHint().width();
 
128
    
 
129
        const int cw = contentsRect().width();
 
130
        const int ch = contentsRect().height();
 
131
 
 
132
        int vw = cw;
 
133
        int vh = ch;
 
134
 
 
135
        if ( w > vw )
 
136
            vh -= sbHeight;
 
137
 
 
138
        if ( h > vh )
 
139
        {
 
140
            vw -= sbWidth;
 
141
            if ( w > vw && vh == ch )
 
142
                vh -= sbHeight;
 
143
        }
 
144
        return QSize(vw, vh);
 
145
    }
 
146
 
 
147
    QWidget *contentsWidget;
 
148
};
 
149
 
 
150
#endif
 
151
 
 
152
 
 
153
void QwtLegend::PrivateData::LegendMap::insert(
 
154
    const QwtPlotItem *item, QWidget *widget)
 
155
{
 
156
    d_itemMap.insert(item, widget);
 
157
    d_widgetMap.insert(widget, item);
 
158
}
 
159
 
 
160
void QwtLegend::PrivateData::LegendMap::remove(const QwtPlotItem *item)
 
161
{
 
162
    QWidget *widget = d_itemMap[item];
 
163
    d_itemMap.remove(item);
 
164
    d_widgetMap.remove(widget);
 
165
}
 
166
 
 
167
void QwtLegend::PrivateData::LegendMap::remove(QWidget *widget)
 
168
{
 
169
    const QwtPlotItem *item = d_widgetMap[widget];
 
170
    d_itemMap.remove(item);
 
171
    d_widgetMap.remove(widget);
 
172
}
 
173
 
 
174
void QwtLegend::PrivateData::LegendMap::clear()
 
175
{
 
176
    
 
177
    /*
 
178
       We can't delete the widgets in the following loop, because
 
179
       we would get ChildRemoved events, changing d_itemMap, while
 
180
       we are iterating.
 
181
     */
 
182
 
 
183
#if QT_VERSION < 0x040000
 
184
    QValueList<QWidget *> widgets;
 
185
 
 
186
    QMap<const QwtPlotItem *, QWidget *>::const_iterator it;
 
187
    for ( it = d_itemMap.begin(); it != d_itemMap.end(); ++it ) 
 
188
        widgets.append(it.data());
 
189
#else
 
190
    QList<QWidget *> widgets;
 
191
 
 
192
    QMap<const QwtPlotItem *, QWidget *>::const_iterator it;
 
193
    for ( it = d_itemMap.begin(); it != d_itemMap.end(); ++it ) 
 
194
        widgets.append(it.value());
 
195
#endif
 
196
 
 
197
    d_itemMap.clear();
 
198
    d_widgetMap.clear();
 
199
 
 
200
    for ( int i = 0; i < (int)widgets.size(); i++ )
 
201
        delete widgets[i];
 
202
}
 
203
 
 
204
uint QwtLegend::PrivateData::LegendMap::count() const
 
205
{
 
206
    return d_itemMap.count();
 
207
}
 
208
 
 
209
inline const QWidget *QwtLegend::PrivateData::LegendMap::find(const QwtPlotItem *item) const
 
210
{
 
211
    if ( !d_itemMap.contains((QwtPlotItem *)item) )
 
212
        return NULL;
 
213
 
 
214
    return d_itemMap[(QwtPlotItem *)item];
 
215
}
 
216
 
 
217
inline QWidget *QwtLegend::PrivateData::LegendMap::find(const QwtPlotItem *item)
 
218
{
 
219
    if ( !d_itemMap.contains((QwtPlotItem *)item) )
 
220
        return NULL;
 
221
 
 
222
    return d_itemMap[(QwtPlotItem *)item];
 
223
}
 
224
 
 
225
inline const QwtPlotItem *QwtLegend::PrivateData::LegendMap::find(
 
226
    const QWidget *widget) const
 
227
{
 
228
    if ( !d_widgetMap.contains((QWidget *)widget) )
 
229
        return NULL;
 
230
 
 
231
    return d_widgetMap[(QWidget *)widget];
 
232
}
 
233
 
 
234
inline QwtPlotItem *QwtLegend::PrivateData::LegendMap::find(
 
235
    const QWidget *widget)
 
236
{
 
237
    if ( !d_widgetMap.contains((QWidget *)widget) )
 
238
        return NULL;
 
239
 
 
240
    return (QwtPlotItem *)d_widgetMap[(QWidget *)widget];
 
241
}
 
242
 
 
243
inline const QMap<QWidget *, const QwtPlotItem *> &
 
244
    QwtLegend::PrivateData::LegendMap::widgetMap() const
 
245
{
 
246
    return d_widgetMap;
 
247
 
248
 
 
249
inline QMap<QWidget *, const QwtPlotItem *> &
 
250
    QwtLegend::PrivateData::LegendMap::widgetMap() 
 
251
{
 
252
    return d_widgetMap;
 
253
 
254
 
 
255
/*!
 
256
  \param parent Parent widget
 
257
*/
 
258
QwtLegend::QwtLegend(QWidget *parent): 
 
259
    QFrame(parent)
 
260
{
 
261
    setFrameStyle(NoFrame);
 
262
 
 
263
    d_data = new QwtLegend::PrivateData;
 
264
    d_data->itemMode = QwtLegend::ReadOnlyItem;
 
265
    d_data->displayPolicy = QwtLegend::AutoIdentifier;
 
266
    d_data->identifierMode = QwtLegendItem::ShowLine | 
 
267
        QwtLegendItem::ShowSymbol | QwtLegendItem::ShowText;
 
268
 
 
269
    d_data->view = new QwtLegend::PrivateData::LegendView(this);
 
270
    d_data->view->setFrameStyle(NoFrame);
 
271
 
 
272
    QwtDynGridLayout *layout = new QwtDynGridLayout(
 
273
        d_data->view->contentsWidget);
 
274
#if QT_VERSION < 0x040000
 
275
    layout->setAutoAdd(true);
 
276
#endif
 
277
    layout->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
 
278
 
 
279
    d_data->view->contentsWidget->installEventFilter(this);
 
280
}
 
281
 
 
282
//! Destructor
 
283
QwtLegend::~QwtLegend()
 
284
{
 
285
    delete d_data;
 
286
}
 
287
 
 
288
/*!
 
289
  Set the legend display policy to:
 
290
 
 
291
  \param policy Legend display policy
 
292
  \param mode Identifier mode (or'd ShowLine, ShowSymbol, ShowText)
 
293
 
 
294
  \sa displayPolicy, LegendDisplayPolicy
 
295
*/
 
296
void QwtLegend::setDisplayPolicy(LegendDisplayPolicy policy, int mode)
 
297
{
 
298
    d_data->displayPolicy = policy;
 
299
    if (-1 != mode)
 
300
       d_data->identifierMode = mode;
 
301
 
 
302
    QMap<QWidget *, const QwtPlotItem *> &map = 
 
303
        d_data->map.widgetMap();
 
304
 
 
305
    QMap<QWidget *, const QwtPlotItem *>::iterator it;
 
306
    for ( it = map.begin(); it != map.end(); ++it ) 
 
307
    {
 
308
#if QT_VERSION < 0x040000
 
309
        QwtPlotItem *item = (QwtPlotItem *)it.data();
 
310
#else
 
311
        QwtPlotItem *item = (QwtPlotItem *)it.value();
 
312
#endif
 
313
        if ( item )
 
314
            item->updateLegend(this);
 
315
    }
 
316
}
 
317
 
 
318
/*! 
 
319
  \return the legend display policy.
 
320
  Default is LegendDisplayPolicy::Auto.
 
321
  \sa setDisplayPolicy, LegendDisplayPolicy
 
322
*/ 
 
323
 
 
324
QwtLegend::LegendDisplayPolicy QwtLegend::displayPolicy() const 
 
325
 
326
    return d_data->displayPolicy; 
 
327
}
 
328
 
 
329
void QwtLegend::setItemMode(LegendItemMode mode)
 
330
{
 
331
    d_data->itemMode = mode;
 
332
}
 
333
 
 
334
QwtLegend::LegendItemMode QwtLegend::itemMode() const
 
335
{
 
336
    return d_data->itemMode;
 
337
}
 
338
 
 
339
/*!
 
340
  \return the IdentifierMode to be used in combination with
 
341
  LegendDisplayPolicy::Fixed.
 
342
 
 
343
  Default is ShowLine | ShowSymbol | ShowText.
 
344
*/
 
345
 
 
346
int QwtLegend::identifierMode() const
 
347
{
 
348
    return d_data->identifierMode;
 
349
}
 
350
 
 
351
/*! 
 
352
  The contents widget is the only child of the viewport() and
 
353
  the parent widget of all legend items.
 
354
*/
 
355
QWidget *QwtLegend::contentsWidget() 
 
356
 
357
    return d_data->view->contentsWidget; 
 
358
}
 
359
 
 
360
QScrollBar *QwtLegend::horizontalScrollBar() const
 
361
{
 
362
    return d_data->view->horizontalScrollBar();
 
363
}
 
364
 
 
365
QScrollBar *QwtLegend::verticalScrollBar() const
 
366
{
 
367
    return d_data->view->horizontalScrollBar();
 
368
}
 
369
 
 
370
/*!  
 
371
  The contents widget is the only child of the viewport() and
 
372
  the parent widget of all legend items.
 
373
*/
 
374
 
 
375
const QWidget *QwtLegend::contentsWidget() const 
 
376
 
377
    return d_data->view->contentsWidget; 
 
378
}
 
379
 
 
380
/*!
 
381
  Insert a new item for a plot item
 
382
  \param plotItem Plot item
 
383
  \param legendItem New legend item
 
384
  \note The parent of item will be changed to QwtLegend::contentsWidget()
 
385
*/
 
386
void QwtLegend::insert(const QwtPlotItem *plotItem, QWidget *legendItem)
 
387
{
 
388
    if ( legendItem == NULL || plotItem == NULL )
 
389
        return;
 
390
 
 
391
    QWidget *contentsWidget = d_data->view->contentsWidget;
 
392
 
 
393
    if ( legendItem->parent() != contentsWidget )
 
394
    {
 
395
#if QT_VERSION >= 0x040000
 
396
        legendItem->setParent(contentsWidget);
 
397
#else
 
398
        legendItem->reparent(contentsWidget, QPoint(0, 0));
 
399
#endif
 
400
    }
 
401
 
 
402
    legendItem->show();
 
403
 
 
404
    d_data->map.insert(plotItem, legendItem);
 
405
 
 
406
    layoutContents();
 
407
 
 
408
    if ( contentsWidget->layout() )
 
409
    {
 
410
#if QT_VERSION >= 0x040000
 
411
        contentsWidget->layout()->addWidget(legendItem);
 
412
#endif
 
413
 
 
414
        // set tab focus chain
 
415
 
 
416
        QWidget *w = NULL;
 
417
 
 
418
#if QT_VERSION < 0x040000
 
419
        QLayoutIterator layoutIterator = 
 
420
            contentsWidget->layout()->iterator();
 
421
        for ( QLayoutItem *item = layoutIterator.current();
 
422
            item != 0; item = ++layoutIterator)
 
423
        {
 
424
#else
 
425
        for (int i = 0; i < contentsWidget->layout()->count(); i++)
 
426
        {
 
427
            QLayoutItem *item = contentsWidget->layout()->itemAt(i);
 
428
#endif
 
429
            if ( w && item->widget() )
 
430
            {
 
431
                QWidget::setTabOrder(w, item->widget());
 
432
                w = item->widget();
 
433
            }
 
434
        }
 
435
    }
 
436
    if ( parentWidget() && parentWidget()->layout() == NULL )
 
437
    {
 
438
       /*
 
439
          updateGeometry() doesn't post LayoutRequest in certain
 
440
          situations, like when we are hidden. But we want the
 
441
          parent widget notified, so it can show/hide the legend
 
442
          depending on its items.
 
443
        */
 
444
#if QT_VERSION < 0x040000
 
445
        QApplication::postEvent(parentWidget(),
 
446
            new QEvent(QEvent::LayoutHint));
 
447
#else
 
448
        QApplication::postEvent(parentWidget(),
 
449
            new QEvent(QEvent::LayoutRequest));
 
450
#endif
 
451
    }
 
452
}
 
453
 
 
454
/*!
 
455
  Find the widget that represents a plot item
 
456
 
 
457
  \param plotItem Plot item
 
458
  \return Widget on the legend, or NULL
 
459
*/
 
460
QWidget *QwtLegend::find(const QwtPlotItem *plotItem) const
 
461
{
 
462
    return d_data->map.find(plotItem);
 
463
}
 
464
 
 
465
/*!
 
466
  Find the widget that represents a plot item
 
467
 
 
468
  \param plotItem Plot item
 
469
  \return Widget on the legend, or NULL
 
470
*/
 
471
QwtPlotItem *QwtLegend::find(const QWidget *legendItem) const
 
472
{
 
473
    return d_data->map.find(legendItem);
 
474
}
 
475
 
 
476
/*! 
 
477
   Find the corresponding item for a plotItem and remove it 
 
478
   from the item list.
 
479
 
 
480
   \param plotItem Plot item
 
481
*/
 
482
void QwtLegend::remove(const QwtPlotItem *plotItem)
 
483
 
484
    QWidget *legendItem = d_data->map.find(plotItem);
 
485
    d_data->map.remove(legendItem); 
 
486
    delete legendItem;
 
487
}
 
488
 
 
489
//! Remove all items.
 
490
void QwtLegend::clear()
 
491
{
 
492
#if QT_VERSION < 0x040000
 
493
    bool doUpdate = isUpdatesEnabled();
 
494
#else
 
495
    bool doUpdate = updatesEnabled();
 
496
#endif
 
497
    setUpdatesEnabled(false);
 
498
 
 
499
    d_data->map.clear();
 
500
 
 
501
    setUpdatesEnabled(doUpdate);
 
502
    update();
 
503
}
 
504
 
 
505
//! Return a size hint.
 
506
QSize QwtLegend::sizeHint() const
 
507
{
 
508
    QSize hint = d_data->view->contentsWidget->sizeHint();
 
509
    hint += QSize(2 * frameWidth(), 2 * frameWidth());
 
510
 
 
511
    return hint;
 
512
}
 
513
 
 
514
/*!
 
515
  \return The preferred height, for the width w.
 
516
  \param width Width
 
517
*/
 
518
int QwtLegend::heightForWidth(int width) const
 
519
{
 
520
    width -= 2 * frameWidth();
 
521
 
 
522
    int h = d_data->view->contentsWidget->heightForWidth(width);
 
523
#if QT_VERSION < 0x040000
 
524
 
 
525
    // Asking the layout is the default implementation in Qt4 
 
526
 
 
527
    if ( h <= 0 ) 
 
528
    {
 
529
        QLayout *l = d_data->view->contentsWidget->layout();
 
530
        if ( l && l->hasHeightForWidth() )
 
531
            h = l->heightForWidth(width);
 
532
    }
 
533
#endif
 
534
    if ( h >= 0 )
 
535
        h += 2 * frameWidth();
 
536
 
 
537
    return h;
 
538
}
 
539
 
 
540
/*!
 
541
  Adjust contents widget and item layout to the size of the viewport().
 
542
*/
 
543
void QwtLegend::layoutContents()
 
544
{
 
545
    const QSize visibleSize = d_data->view->viewport()->size();
 
546
 
 
547
    const QLayout *l = d_data->view->contentsWidget->layout();
 
548
    if ( l && l->inherits("QwtDynGridLayout") )
 
549
    {
 
550
        const QwtDynGridLayout *tl = (const QwtDynGridLayout *)l;
 
551
 
 
552
        const int minW = int(tl->maxItemWidth()) + 2 * tl->margin();
 
553
 
 
554
        int w = qwtMax(visibleSize.width(), minW);
 
555
        int h = qwtMax(tl->heightForWidth(w), visibleSize.height());
 
556
 
 
557
        const int vpWidth = d_data->view->viewportSize(w, h).width();
 
558
        if ( w > vpWidth )
 
559
        {
 
560
            w = qwtMax(vpWidth, minW);
 
561
            h = qwtMax(tl->heightForWidth(w), visibleSize.height());
 
562
        }
 
563
 
 
564
        d_data->view->contentsWidget->resize(w, h);
 
565
#if QT_VERSION < 0x040000
 
566
        d_data->view->resizeContents(w, h);
 
567
#endif
 
568
    }
 
569
}
 
570
 
 
571
/*
 
572
  Filter layout related events of QwtLegend::contentsWidget().
 
573
 
 
574
  \param o Object to be filtered
 
575
  \param e Event
 
576
*/
 
577
 
 
578
bool QwtLegend::eventFilter(QObject *o, QEvent *e)
 
579
{
 
580
    if ( o == d_data->view->contentsWidget )
 
581
    {
 
582
        switch(e->type())
 
583
        {
 
584
            case QEvent::ChildRemoved:
 
585
            {   
 
586
                const QChildEvent *ce = (const QChildEvent *)e;
 
587
                if ( ce->child()->isWidgetType() )
 
588
                    d_data->map.remove((QWidget *)ce->child());
 
589
                break;
 
590
            }
 
591
#if QT_VERSION < 0x040000
 
592
            case QEvent::LayoutHint:
 
593
#else
 
594
            case QEvent::LayoutRequest:
 
595
#endif
 
596
            {
 
597
                layoutContents();
 
598
                break;
 
599
            }
 
600
#if QT_VERSION < 0x040000
 
601
            case QEvent::Resize:
 
602
            {
 
603
                updateGeometry();
 
604
                break;
 
605
            }
 
606
#endif
 
607
            default:
 
608
                break;
 
609
        }
 
610
    }
 
611
    
 
612
    return QFrame::eventFilter(o, e);
 
613
}
 
614
 
 
615
 
 
616
//! Return true, if there are no legend items.
 
617
bool QwtLegend::isEmpty() const
 
618
{
 
619
    return d_data->map.count() == 0;
 
620
}
 
621
 
 
622
//! Return the number of legend items.
 
623
uint QwtLegend::itemCount() const
 
624
{
 
625
    return d_data->map.count();
 
626
}
 
627
 
 
628
#if QT_VERSION < 0x040000
 
629
QValueList<QWidget *> QwtLegend::legendItems() const
 
630
#else
 
631
QList<QWidget *> QwtLegend::legendItems() const
 
632
#endif
 
633
{
 
634
    const QMap<QWidget *, const QwtPlotItem *> &map = 
 
635
        d_data->map.widgetMap();
 
636
 
 
637
#if QT_VERSION < 0x040000
 
638
    QValueList<QWidget *> list;
 
639
#else
 
640
    QList<QWidget *> list;
 
641
#endif
 
642
 
 
643
    QMap<QWidget *, const QwtPlotItem *>::const_iterator it;
 
644
    for ( it = map.begin(); it != map.end(); ++it ) 
 
645
        list += it.key();
 
646
 
 
647
    return list;
 
648
}
 
649
 
 
650
/*!
 
651
   Resize event
 
652
   \param e Event
 
653
*/
 
654
void QwtLegend::resizeEvent(QResizeEvent *e)
 
655
{
 
656
    QFrame::resizeEvent(e);
 
657
    d_data->view->setGeometry(contentsRect());
 
658
}