1 #include "legend.h"
2 #include <qwt_legend_data.h>
3 #include <qwt_text.h>
4 #include <qwt_plot_item.h>
5 #include <qtreeview.h>
6 #include <qlayout.h>
7 #include <qstyle.h>
8 #include <qstandarditemmodel.h>
9 #include <qitemdelegate.h>
10 #include <qpainter.h>
11 
qwtRenderBackground(QPainter * painter,const QRectF & rect,const QWidget * widget)12 static void qwtRenderBackground( QPainter *painter,
13     const QRectF &rect, const QWidget *widget )
14 {
15     if ( widget->testAttribute( Qt::WA_StyledBackground ) )
16     {
17         QStyleOption opt;
18         opt.initFrom( widget );
19         opt.rect = rect.toAlignedRect();
20 
21         widget->style()->drawPrimitive(
22             QStyle::PE_Widget, &opt, painter, widget);
23     }
24     else
25     {
26         const QBrush brush =
27             widget->palette().brush( widget->backgroundRole() );
28 
29         painter->fillRect( rect, brush );
30     }
31 }
32 
33 class LegendTreeView: public QTreeView
34 {
35 public:
36     LegendTreeView( Legend * );
37 
38     QStandardItem *rootItem( int rtti );
39     QStandardItem *insertRootItem( int rtti );
40 
41     QList<QStandardItem *> itemList( const QwtPlotItem * );
42 
43     virtual QSize sizeHint() const;
44     virtual QSize minimumSizeHint() const;
45 };
46 
LegendTreeView(Legend * legend)47 LegendTreeView::LegendTreeView( Legend *legend ):
48     QTreeView( legend )
49 {
50     setFrameStyle( NoFrame );
51     viewport()->setBackgroundRole(QPalette::Background);
52     viewport()->setAutoFillBackground( false );
53 
54     setRootIsDecorated( true );
55     setHeaderHidden( true );
56 
57     QStandardItemModel *model = new QStandardItemModel();
58 
59     setModel( model );
60 
61     // we want unstyled items
62     setItemDelegate( new QItemDelegate( this ) );
63 }
64 
rootItem(int rtti)65 QStandardItem *LegendTreeView::rootItem( int rtti )
66 {
67     QStandardItemModel *mdl =
68         qobject_cast<QStandardItemModel *>( model() );
69 
70     for ( int row = 0; row < mdl->rowCount(); row++ )
71     {
72         QStandardItem *item = mdl->item( row );
73         if ( item->data() == rtti )
74             return item;
75     }
76 
77     return NULL;
78 }
79 
itemList(const QwtPlotItem * plotItem)80 QList<QStandardItem *> LegendTreeView::itemList(
81     const QwtPlotItem *plotItem )
82 {
83     QList<QStandardItem *> itemList;
84 
85     const QStandardItem *rootItem = this->rootItem( plotItem->rtti() );
86     if ( rootItem )
87     {
88         for ( int i = 0; i < rootItem->rowCount(); i++ )
89         {
90             QStandardItem *item = rootItem->child( i );
91 
92             const QVariant key = item->data();
93 
94             if ( key.canConvert<qlonglong>() )
95             {
96                 const qlonglong ptr = key.value<qlonglong>();
97                 if ( ptr == qlonglong( plotItem ) )
98                     itemList += item;
99             }
100         }
101     }
102 
103     return itemList;
104 }
105 
insertRootItem(int rtti)106 QStandardItem *LegendTreeView::insertRootItem( int rtti )
107 {
108     QStandardItem *item = new QStandardItem();
109     item->setEditable( false );
110     item->setData( rtti );
111 
112     switch( rtti )
113     {
114         case QwtPlotItem::Rtti_PlotTradingCurve:
115         {
116             item->setText( "Curves" );
117             break;
118         }
119         case QwtPlotItem::Rtti_PlotZone:
120         {
121             item->setText( "Zones" );
122             break;
123         }
124         case QwtPlotItem::Rtti_PlotMarker:
125         {
126             item->setText( "Events" );
127             break;
128         }
129         default:
130             break;
131     }
132 
133     QStandardItemModel *mdl =
134         qobject_cast<QStandardItemModel *>( model() );
135 
136     mdl->appendRow( item );
137     setExpanded( mdl->index( mdl->rowCount() - 1, 0 ), true );
138 
139     return item;
140 }
141 
minimumSizeHint() const142 QSize LegendTreeView::minimumSizeHint() const
143 {
144     return QSize( -1, -1 );
145 }
146 
sizeHint() const147 QSize LegendTreeView::sizeHint() const
148 {
149     QStyleOptionViewItem styleOption;
150     styleOption.initFrom( this );
151 
152     const QAbstractItemDelegate *delegate = itemDelegate();
153 
154     const QStandardItemModel *mdl =
155         qobject_cast<const QStandardItemModel *>( model() );
156 
157     int w = 0;
158     int h = 0;
159 
160     for ( int row = 0; row < mdl->rowCount(); row++ )
161     {
162         const QStandardItem *rootItem = mdl->item( row );
163 
164         int wRow = 0;
165         for ( int i = 0; i < rootItem->rowCount(); i++ )
166         {
167             const QSize hint = delegate->sizeHint( styleOption,
168                 rootItem->child( i )->index() );
169 
170             wRow = qMax( wRow, hint.width() );
171             h += hint.height();
172         }
173 
174         const QSize rootHint = delegate->sizeHint(
175             styleOption, rootItem->index() );
176 
177         wRow = qMax( wRow + indentation(), rootHint.width() );
178         if ( wRow > w )
179             w = wRow;
180 
181         if ( rootIsDecorated() )
182             w += indentation();
183 
184         h += rootHint.height();
185     }
186 
187     int left, right, top, bottom;
188     getContentsMargins( &left, &top, &right, &bottom );
189 
190     w += left + right;
191     h += top + bottom;
192 
193     return QSize( w, h );
194 }
195 
Legend(QWidget * parent)196 Legend::Legend( QWidget *parent ):
197     QwtAbstractLegend( parent )
198 {
199     d_treeView = new LegendTreeView( this );
200 
201     QVBoxLayout *layout = new QVBoxLayout( this );
202     layout->setContentsMargins( 0, 0, 0, 0 );
203     layout->addWidget( d_treeView );
204 
205     connect( d_treeView, SIGNAL( clicked( const QModelIndex & ) ),
206         this, SLOT( handleClick( const QModelIndex & ) ) );
207 }
208 
~Legend()209 Legend::~Legend()
210 {
211 }
212 
renderLegend(QPainter * painter,const QRectF & rect,bool fillBackground) const213 void Legend::renderLegend( QPainter *painter,
214     const QRectF &rect, bool fillBackground ) const
215 {
216     if ( fillBackground )
217     {
218         if ( autoFillBackground() ||
219             testAttribute( Qt::WA_StyledBackground ) )
220         {
221             qwtRenderBackground( painter, rect, d_treeView );
222         }
223     }
224 
225     QStyleOptionViewItem styleOption;
226     styleOption.initFrom( this );
227     styleOption.decorationAlignment = Qt::AlignCenter;
228 
229     const QAbstractItemDelegate *delegate = d_treeView->itemDelegate();
230 
231     const QStandardItemModel *mdl =
232         qobject_cast<const QStandardItemModel *>( d_treeView->model() );
233 
234     painter->save();
235     painter->translate( rect.topLeft() );
236 
237     for ( int row = 0; row < mdl->rowCount(); row++ )
238     {
239         const QStandardItem *rootItem = mdl->item( row );
240 
241         styleOption.rect = d_treeView->visualRect( rootItem->index() );
242         if ( !styleOption.rect.isEmpty() )
243             delegate->paint( painter, styleOption, rootItem->index() );
244 
245         for ( int i = 0; i < rootItem->rowCount(); i++ )
246         {
247             const QStandardItem *item = rootItem->child( i );
248 
249             styleOption.rect = d_treeView->visualRect( item->index() );
250             if ( !styleOption.rect.isEmpty() )
251             {
252                 delegate->paint( painter, styleOption, item->index() );
253             }
254         }
255     }
256     painter->restore();
257 }
258 
isEmpty() const259 bool Legend::isEmpty() const
260 {
261     return d_treeView->model()->rowCount() == 0;
262 }
263 
scrollExtent(Qt::Orientation orientation) const264 int Legend::scrollExtent( Qt::Orientation orientation ) const
265 {
266     Q_UNUSED( orientation );
267 
268     return style()->pixelMetric( QStyle::PM_ScrollBarExtent );
269 }
270 
updateLegend(const QVariant & itemInfo,const QList<QwtLegendData> & legendData)271 void Legend::updateLegend( const QVariant &itemInfo,
272     const QList<QwtLegendData> &legendData )
273 {
274     QwtPlotItem *plotItem = qvariant_cast<QwtPlotItem *>( itemInfo );
275 
276     QStandardItem *rootItem = d_treeView->rootItem( plotItem->rtti() );
277     QList<QStandardItem *> itemList = d_treeView->itemList( plotItem );
278 
279     while ( itemList.size() > legendData.size() )
280     {
281         QStandardItem *item = itemList.takeLast();
282         rootItem->removeRow( item->row() );
283     }
284 
285     if ( !legendData.isEmpty() )
286     {
287         if ( rootItem == NULL )
288             rootItem = d_treeView->insertRootItem( plotItem->rtti() );
289 
290         while ( itemList.size() < legendData.size() )
291         {
292             QStandardItem *item = new QStandardItem();
293             item->setEditable( false );
294             item->setData( qlonglong( plotItem ) );
295             item->setCheckable( true );
296             item->setCheckState( plotItem->isVisible() ?
297                 Qt::Checked : Qt::Unchecked );
298 
299             itemList += item;
300             rootItem->appendRow( item );
301         }
302 
303         for ( int i = 0; i < itemList.size(); i++ )
304             updateItem( itemList[i], legendData[i] );
305     }
306     else
307     {
308         if ( rootItem && rootItem->rowCount() == 0 )
309             d_treeView->model()->removeRow( rootItem->row() );
310     }
311 
312     d_treeView->updateGeometry();
313 }
314 
updateItem(QStandardItem * item,const QwtLegendData & legendData)315 void Legend::updateItem( QStandardItem *item, const QwtLegendData &legendData )
316 {
317     const QVariant titleValue = legendData.value( QwtLegendData::TitleRole );
318 
319     QwtText title;
320     if ( titleValue.canConvert<QwtText>() )
321     {
322         item->setText( title.text() );
323         title = titleValue.value<QwtText>();
324     }
325     else if ( titleValue.canConvert<QString>() )
326     {
327         title.setText( titleValue.value<QString>() );
328     }
329     item->setText( title.text() );
330 
331     const QVariant iconValue = legendData.value( QwtLegendData::IconRole );
332 
333     QPixmap pm;
334     if ( iconValue.canConvert<QPixmap>() )
335         pm = iconValue.value<QPixmap>();
336 
337     item->setData(pm, Qt::DecorationRole);
338 }
339 
handleClick(const QModelIndex & index)340 void Legend::handleClick( const QModelIndex &index )
341 {
342     const QStandardItemModel *model =
343         qobject_cast<QStandardItemModel *>( d_treeView->model() );
344 
345     const QStandardItem *item = model->itemFromIndex( index );
346     if ( item->isCheckable() )
347     {
348         const qlonglong ptr = item->data().value<qlonglong>();
349 
350         Q_EMIT checked( (QwtPlotItem *)ptr,
351             item->checkState() == Qt::Checked, 0 );
352     }
353 }
354