00001 #include <qlayout.h> 00002 #include <qpen.h> 00003 #include <QSettings> 00004 #include "qwt_plot.h" 00005 #include "qwt_plot_canvas.h" 00006 #include "qwt_scale_widget.h" 00007 #include "qwt_scale_draw.h" 00008 #include "plotmatrix.h" 00009 #include "customtracker.h" 00010 00011 static int widget_uid = 0; 00012 00013 PlotMatrix::PlotMatrix(QString name, PlotDataMapRef &datamap, QWidget *parent ): 00014 QFrame( parent ), 00015 _mapped_data(datamap), 00016 _name(name) 00017 { 00018 _num_rows = 0; 00019 _num_cols = 0; 00020 _layout = new QGridLayout( this ); 00021 _horizontal_link = true; 00022 QSettings settings; 00023 00024 _legend_point_size = settings.value("PlotMatrix/legend_point_size", 9).toInt(); 00025 updateLayout(); 00026 } 00027 00028 00029 PlotWidget* PlotMatrix::addPlotWidget(unsigned row, unsigned col) 00030 { 00031 PlotWidget *plot = new PlotWidget( _mapped_data, this ); 00032 00033 plot->setWindowTitle(QString("PlotWidget ") + QString::number(widget_uid++)); 00034 00035 connect( plot, &PlotWidget::rectChanged, 00036 this, &PlotMatrix::on_singlePlotScaleChanged); 00037 00038 connect( plot, &PlotWidget::legendSizeChanged, 00039 this, &PlotMatrix::on_legendSizeChanged); 00040 00041 plot->setLegendSize( _legend_point_size ); 00042 00043 plot->setAttribute(Qt::WA_DeleteOnClose); 00044 00045 _layout->addWidget( plot, row, col ); 00046 _layout->setRowStretch(row,1); 00047 _layout->setColumnStretch(col,1); 00048 00049 emit plotAdded(plot); 00050 00051 return plot; 00052 } 00053 00054 void PlotMatrix::addRow() 00055 { 00056 if( _num_rows==0 && _num_cols==0 ) 00057 { 00058 addPlotWidget( 0, 0 ); 00059 _num_rows = 1; 00060 _num_cols = 1; 00061 } 00062 else{ 00063 for ( unsigned col = 0; col < colsCount(); col++ ) { 00064 addPlotWidget( _num_rows, col ); 00065 } 00066 _num_rows++; 00067 } 00068 00069 updateLayout(); 00070 } 00071 00072 void PlotMatrix::addColumn() 00073 { 00074 if( _num_rows==0 && _num_cols==0 ) 00075 { 00076 addPlotWidget( 0, 0 ); 00077 _num_rows = 1; 00078 _num_cols = 1; 00079 } 00080 else { 00081 for ( unsigned row = 0; row < rowsCount(); row++ ) 00082 { 00083 addPlotWidget( row, _num_cols ); 00084 } 00085 _num_cols++; 00086 } 00087 updateLayout(); 00088 } 00089 00090 void PlotMatrix::swapPlots( unsigned rowA, unsigned colA, unsigned rowB, unsigned colB) 00091 { 00092 QWidget *widgetA = _layout->itemAtPosition(rowA, colA)->widget(); 00093 QWidget *widgetB = _layout->itemAtPosition(rowB, colB)->widget(); 00094 00095 _layout->removeItem( _layout->itemAtPosition(rowA, colA) ); 00096 _layout->removeItem( _layout->itemAtPosition(rowB, colB) ); 00097 00098 _layout->addWidget(widgetA, rowB, colB); 00099 _layout->addWidget(widgetB, rowA, colA); 00100 updateLayout(); 00101 } 00102 00103 void PlotMatrix::removeColumn(unsigned column_to_delete) 00104 { 00105 if(_num_rows==1 && _num_cols ==1 ) { 00106 return; 00107 } 00108 00109 for(unsigned col = column_to_delete; col< _num_cols-1; col++) 00110 { 00111 for(unsigned row=0; row< _num_rows; row++) 00112 { 00113 this->swapPlots( row, col, row, col+1); 00114 } 00115 } 00116 for(unsigned row=0; row< _num_rows; row++) 00117 { 00118 plotAt( row, _num_cols -1)->close(); 00119 } 00120 _layout->setColumnStretch(_num_cols -1,0); 00121 00122 _num_cols--; 00123 if( _num_cols == 0){ 00124 _num_rows = 0; 00125 } 00126 00127 updateLayout(); 00128 00129 } 00130 00131 void PlotMatrix::removeRow(unsigned row_to_delete) 00132 { 00133 if(_num_rows==1 && _num_cols ==1 ) { 00134 return; 00135 } 00136 for(unsigned row = row_to_delete; row< _num_rows-1; row++) 00137 { 00138 for(unsigned col = 0; col< _num_cols; col++) 00139 { 00140 this->swapPlots( row, col, row+1, col); 00141 } 00142 } 00143 for(unsigned col=0; col< _num_cols; col++) 00144 { 00145 plotAt( _num_rows-1, col)->close(); 00146 } 00147 _layout->setRowStretch(_num_rows -1,0); 00148 00149 _num_rows--; 00150 if( _num_rows == 0){ 00151 _num_cols = 0; 00152 } 00153 00154 updateLayout(); 00155 } 00156 00157 void PlotMatrix::removeEmpty() 00158 { 00159 for( unsigned row = 0; row< rowsCount(); row++) 00160 { 00161 while( rowsCount() > 1 && 00162 isRowEmpty( row ) && 00163 row < rowsCount() ) 00164 { 00165 removeRow( row ); 00166 } 00167 } 00168 00169 for( unsigned col = 0; col< colsCount(); col++) 00170 { 00171 while( colsCount() > 1 && 00172 isColumnEmpty( col ) && 00173 col < colsCount() ) 00174 { 00175 removeColumn( col ); 00176 } 00177 } 00178 } 00179 00180 00181 PlotMatrix::~PlotMatrix(){} 00182 00183 unsigned PlotMatrix::rowsCount() const 00184 { 00185 return _num_rows; 00186 } 00187 00188 unsigned PlotMatrix::colsCount() const 00189 { 00190 return _num_cols; 00191 } 00192 00193 unsigned PlotMatrix::plotCount() const 00194 { 00195 return _num_rows*_num_cols; 00196 } 00197 00198 bool PlotMatrix::isColumnEmpty( unsigned col ) const 00199 { 00200 for (int r=0; r < _layout->rowCount(); r++) 00201 { 00202 auto plot = plotAt(r, col); 00203 if( plot && ! plot->isEmpty() ) { 00204 return false; 00205 } 00206 } 00207 return true; 00208 } 00209 00210 bool PlotMatrix::isRowEmpty(unsigned row ) const 00211 { 00212 for (int c=0; c< _layout->columnCount(); c++) 00213 { 00214 auto plot = plotAt(row, c); 00215 if( plot && ! plot->isEmpty() ) { 00216 return false; 00217 } 00218 } 00219 return true; 00220 } 00221 00222 00223 PlotWidget* PlotMatrix::plotAt( unsigned row, unsigned column ) 00224 { 00225 QLayoutItem* item = _layout->itemAtPosition(row,column); 00226 if(item) { 00227 PlotWidget* plot = static_cast<PlotWidget*>( item->widget() ); 00228 return plot; 00229 } 00230 return NULL; 00231 } 00232 00233 const PlotWidget* PlotMatrix::plotAt( unsigned row, unsigned column ) const 00234 { 00235 QLayoutItem* item = _layout->itemAtPosition(row,column); 00236 if(item) { 00237 PlotWidget* plot = static_cast<PlotWidget*>( item->widget() ); 00238 return plot; 00239 } 00240 return NULL; 00241 } 00242 00243 PlotWidget* PlotMatrix::plotAt( unsigned index ) 00244 { 00245 return plotAt(index% rowsCount(), index/rowsCount()); 00246 } 00247 00248 const PlotWidget* PlotMatrix::plotAt( unsigned index ) const 00249 { 00250 return plotAt(index% rowsCount(), index/rowsCount()); 00251 } 00252 00253 00254 void PlotMatrix::setAxisScale(QwtPlot::Axis axisId, unsigned row, unsigned col, 00255 double min, double max, double step ) 00256 { 00257 PlotWidget *plt = plotAt( row, col ); 00258 if ( plt ) 00259 { 00260 plt->setAxisScale( axisId, min, max, step ); 00261 plt->updateAxes(); 00262 } 00263 } 00264 00265 QDomElement PlotMatrix::xmlSaveState( QDomDocument &doc ) const 00266 { 00267 QDomElement element = doc.createElement("plotmatrix"); 00268 00269 element.setAttribute("rows", _num_rows ); 00270 element.setAttribute("columns", _num_cols ); 00271 00272 for(unsigned col = 0; col< _num_cols; col++) 00273 { 00274 for(unsigned row = 0; row< _num_rows; row++) 00275 { 00276 const PlotWidget* plot = plotAt(row,col); 00277 QDomElement child = plot->xmlSaveState(doc); 00278 00279 child.setAttribute("row", row); 00280 child.setAttribute("col", col); 00281 00282 element.appendChild( child ); 00283 } 00284 } 00285 return element; 00286 } 00287 00288 bool PlotMatrix::xmlLoadState( QDomElement &plotmatrix ) 00289 { 00290 if( !plotmatrix.hasAttribute("rows") || !plotmatrix.hasAttribute("columns") ) 00291 { 00292 qWarning() << "No [rows] or [columns] attribute in <plotmatrix> XML file!"; 00293 return false; 00294 } 00295 unsigned rows = plotmatrix.attribute("rows").toUInt(); 00296 unsigned cols = plotmatrix.attribute("columns" ).toUInt(); 00297 00298 while( rows > _num_rows){ addRow(); } 00299 while( rows < _num_rows){ removeRow( _num_rows-1 ); } 00300 00301 while( cols > _num_cols){ addColumn(); } 00302 while( cols < _num_cols){ removeColumn( _num_cols-1 ); } 00303 00304 QDomElement plot_element; 00305 for ( plot_element = plotmatrix.firstChildElement( "plot" ) ; 00306 !plot_element.isNull(); 00307 plot_element = plot_element.nextSiblingElement( "plot" ) ) 00308 { 00309 if( !plot_element.hasAttribute("row") || !plot_element.hasAttribute("col") ) 00310 { 00311 qWarning() << "No [row] or [col] attribute in <plot> XML file!"; 00312 return false; 00313 } 00314 unsigned row = plot_element.attribute("row").toUInt(); 00315 unsigned col = plot_element.attribute("col").toUInt(); 00316 00317 bool success = plotAt(row,col)->xmlLoadState( plot_element ) ; 00318 if( !success ) 00319 { 00320 return false; 00321 } 00322 } 00323 return true; 00324 } 00325 00326 00327 00328 void PlotMatrix::updateLayout() 00329 { 00330 for ( unsigned row = 0; row < rowsCount(); row++ ) 00331 { 00332 alignAxes( row, QwtPlot::xBottom ); 00333 alignScaleBorder( row, QwtPlot::yLeft ); 00334 } 00335 00336 for ( unsigned col = 0; col < colsCount(); col++ ) 00337 { 00338 alignAxes( col, QwtPlot::yLeft ); 00339 alignScaleBorder( col, QwtPlot::xBottom ); 00340 } 00341 } 00342 00343 void PlotMatrix::replot() 00344 { 00345 for ( unsigned i = 0; i< plotCount(); i++ ) 00346 { 00347 PlotWidget *plot = plotAt(i); 00348 plot->replot(); 00349 } 00350 } 00351 00352 00353 void PlotMatrix::setHorizontalLink(bool linked) 00354 { 00355 _horizontal_link = linked; 00356 } 00357 00358 00359 void PlotMatrix::setName(const QString &new_name) 00360 { 00361 _name = new_name; 00362 } 00363 00364 const QString &PlotMatrix::name() const 00365 { 00366 return _name; 00367 } 00368 00369 QGridLayout *PlotMatrix::gridLayout() 00370 { 00371 return _layout; 00372 } 00373 00374 void PlotMatrix::maximumZoomOutHorizontal() 00375 { 00376 for ( unsigned i = 0; i< plotCount(); i++ ) 00377 { 00378 PlotWidget *plot = plotAt(i); 00379 if( plot->isEmpty() == false) 00380 { 00381 plot->on_zoomOutHorizontal_triggered( false ); 00382 } 00383 } 00384 replot(); 00385 } 00386 00387 void PlotMatrix::maximumZoomOutVertical() 00388 { 00389 for ( unsigned i = 0; i < plotCount(); i++ ) 00390 { 00391 PlotWidget *plot = plotAt(i); 00392 if( plot->isEmpty() == false) 00393 { 00394 plot->on_zoomOutVertical_triggered(false); 00395 } 00396 } 00397 replot(); 00398 } 00399 00400 void PlotMatrix::maximumZoomOut() 00401 { 00402 for ( unsigned i = 0; i < plotCount(); i++ ) 00403 { 00404 PlotWidget *plot = plotAt(i); 00405 if( plot->isEmpty() == false) 00406 { 00407 plot->zoomOut(false); 00408 } 00409 } 00410 replot(); 00411 } 00412 00413 00414 void PlotMatrix::on_singlePlotScaleChanged(PlotWidget *modified_plot, QRectF new_range) 00415 { 00416 if( _horizontal_link ) 00417 { 00418 for ( unsigned i = 0; i< plotCount(); i++ ) 00419 { 00420 PlotWidget *plot = plotAt(i); 00421 if( plot->isEmpty() == false && 00422 modified_plot != plot && 00423 plot->isXYPlot() == false) 00424 { 00425 QRectF bound_act = plot->canvasBoundingRect(); 00426 bound_act.setLeft( new_range.left() ); 00427 bound_act.setRight( new_range.right() ); 00428 plot->setZoomRectangle( bound_act, false ); 00429 plot->on_zoomOutVertical_triggered(false); 00430 plot->replot(); 00431 } 00432 } 00433 } 00434 emit undoableChange(); 00435 } 00436 00437 void PlotMatrix::on_legendSizeChanged(int point_size) 00438 { 00439 _legend_point_size = point_size; 00440 00441 QSettings settings; 00442 settings.setValue("PlotMatrix/legend_point_size", _legend_point_size); 00443 00444 for ( unsigned i = 0; i< plotCount(); i++ ) 00445 { 00446 PlotWidget *plot = plotAt(i); 00447 plot->setLegendSize(point_size); 00448 } 00449 } 00450 00451 void PlotMatrix::alignAxes( unsigned rowOrColumn, QwtPlot::Axis axisId ) 00452 { 00453 bool iterating_rows = ( axisId == QwtPlot::yLeft || axisId == QwtPlot::yRight ); 00454 const int COUNT = iterating_rows ? rowsCount() : colsCount(); 00455 00456 double maxExtent = 0; 00457 00458 for ( unsigned i = 0; i < COUNT; i++ ) 00459 { 00460 QwtPlot *p = iterating_rows? plotAt( i, rowOrColumn ) : plotAt( rowOrColumn, i ); 00461 if ( p ) 00462 { 00463 QwtScaleWidget *scaleWidget = p->axisWidget( axisId ); 00464 00465 QwtScaleDraw *sd = scaleWidget->scaleDraw(); 00466 sd->setMinimumExtent( 0.0 ); 00467 00468 const double extent = sd->extent( scaleWidget->font() ); 00469 if ( extent > maxExtent ) 00470 maxExtent = extent; 00471 } 00472 } 00473 00474 for ( unsigned i = 0; i < COUNT; i++ ) 00475 { 00476 QwtPlot *p = iterating_rows? plotAt( i, rowOrColumn ) : plotAt( rowOrColumn, i ); 00477 if ( p ) 00478 { 00479 QwtScaleWidget *scaleWidget = p->axisWidget( axisId ); 00480 scaleWidget->scaleDraw()->setMinimumExtent( maxExtent ); 00481 } 00482 } 00483 } 00484 00485 void PlotMatrix::alignScaleBorder(unsigned rowOrColumn, QwtPlot::Axis axisId ) 00486 { 00487 if ( axisId == QwtPlot::yLeft || axisId == QwtPlot::yRight ) 00488 { 00489 for ( unsigned col = 0; col < colsCount(); col++ ) 00490 { 00491 QwtPlot *p = plotAt( rowOrColumn, col ); 00492 if ( p ) 00493 p->axisWidget( axisId )->setMinBorderDist( 10, 10 ); 00494 } 00495 } 00496 else if ( axisId == QwtPlot::xTop || axisId == QwtPlot::xBottom ) 00497 { 00498 for ( unsigned row = 0; row < rowsCount(); row++ ) 00499 { 00500 QwtPlot *p = plotAt( row, rowOrColumn ); 00501 if ( p ) 00502 p->axisWidget( axisId )->setMinBorderDist( 15, 15 ); 00503 } 00504 } 00505 }