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