tabbedplotwidget.cpp
Go to the documentation of this file.
00001 #include <QMenu>
00002 #include <QSignalMapper>
00003 #include <QAction>
00004 #include <QInputDialog>
00005 #include <QMouseEvent>
00006 #include <QFileDialog>
00007 #include <QApplication>
00008 #include "qwt_plot_renderer.h"
00009 #include "mainwindow.h"
00010 #include "tabbedplotwidget.h"
00011 #include "tab_widget.h"
00012 #include "ui_tabbedplotwidget.h"
00013 
00014 std::map<QString,TabbedPlotWidget*> TabbedPlotWidget::_instances;
00015 
00016 TabbedPlotWidget::TabbedPlotWidget(QString name,
00017                                    QMainWindow *main_window_,
00018                                    PlotMatrix  *first_tab,
00019                                    PlotDataMapRef &mapped_data,
00020                                    QMainWindow *parent ) :
00021     QWidget(parent),
00022     _mapped_data(mapped_data),
00023     ui(new Ui::TabbedPlotWidget),
00024     _name(name),
00025     _labels_status (LabelStatus::RIGHT)
00026 {
00027     MainWindow* main_window = static_cast<MainWindow*>(main_window_);
00028 
00029     if( main_window == parent){
00030         _parent_type = "main_window";
00031     }
00032     else
00033     {
00034         _parent_type = "floating_window";
00035     }
00036 
00037     if( TabbedPlotWidget::_instances.count(_name) > 0)
00038     {
00039         throw std::runtime_error("This is not supposed to happen");
00040     }
00041     // register this instance
00042     _instances[_name] = this;
00043 
00044     ui->setupUi(this);
00045 
00046     _horizontal_link = true;
00047 
00048     tabWidget()->tabBar()->installEventFilter( this );
00049 
00050     _action_renameTab = new QAction(tr("Rename tab"), this);
00051     connect( _action_renameTab, &QAction::triggered, this, &TabbedPlotWidget::on_renameCurrentTab);
00052 
00053     QIcon iconSave;
00054     iconSave.addFile(QStringLiteral(":/icons/resources/light/save.png"), QSize(26, 26));
00055     _action_savePlots = new  QAction(tr("&Save plots to file"), this);
00056     _action_savePlots->setIcon(iconSave);
00057     connect(_action_savePlots, &QAction::triggered, this, &TabbedPlotWidget::on_savePlotsToFile);
00058 
00059     _tab_menu = new QMenu(this);
00060     _tab_menu->addAction( _action_renameTab );
00061     _tab_menu->addSeparator();
00062     _tab_menu->addAction( _action_savePlots );
00063     _tab_menu->addSeparator();
00064 
00065     connect( this, &TabbedPlotWidget::destroyed,          main_window, &MainWindow::on_tabbedAreaDestroyed );
00066     connect( this, &TabbedPlotWidget::sendTabToNewWindow, main_window, &MainWindow::onCreateFloatingWindow);
00067     connect( this, &TabbedPlotWidget::matrixAdded,        main_window, &MainWindow::onPlotMatrixAdded);
00068     connect( this, &TabbedPlotWidget::undoableChangeHappened, main_window, &MainWindow::onUndoableChange);
00069 
00070     connect( ui->tabWidget, &TabWidget::movingPlotWidgetToTab, this, &TabbedPlotWidget::onMoveWidgetIntoNewTab);
00071 
00072     this->addTab(first_tab);
00073 }
00074 
00075 //void TabbedPlotWidget::setSiblingsList(const std::map<QString, TabbedPlotWidget *> &other_tabbed_widgets)
00076 //{
00077 //    _other_siblings = other_tabbed_widgets;
00078 //}
00079 
00080 PlotMatrix *TabbedPlotWidget::currentTab()
00081 {
00082     return static_cast<PlotMatrix*>( tabWidget()->currentWidget() );
00083 }
00084 
00085 QTabWidget *TabbedPlotWidget::tabWidget()
00086 {
00087     return ui->tabWidget;
00088 }
00089 
00090 const QTabWidget* TabbedPlotWidget::tabWidget() const
00091 {
00092     return ui->tabWidget;
00093 }
00094 
00095 
00096 void TabbedPlotWidget::addTab( PlotMatrix* tab)
00097 {
00098     if( !tab )
00099     {
00100         tab = new PlotMatrix("plot", _mapped_data, this);
00101         tabWidget()->addTab( tab, QString("plot") );
00102 
00103         QApplication::processEvents();
00104         emit matrixAdded( tab );
00105         tab->addColumn();
00106     }
00107     else{
00108         tabWidget()->addTab( tab, tab->name() );
00109     }
00110 
00111     tabWidget()->setCurrentWidget( tab );
00112     tab->setHorizontalLink( _horizontal_link );
00113 }
00114 
00115 QDomElement TabbedPlotWidget::xmlSaveState(QDomDocument &doc) const
00116 {
00117     QDomElement tabbed_area = doc.createElement( "tabbed_widget" );
00118 
00119     tabbed_area.setAttribute("name",   _name);
00120     tabbed_area.setAttribute("parent", _parent_type);
00121 
00122     for(int i=0; i< tabWidget()->count(); i++)
00123     {
00124         PlotMatrix* widget = static_cast<PlotMatrix*>( tabWidget()->widget(i) );
00125         QDomElement element = widget->xmlSaveState(doc);
00126 
00127         element.setAttribute("tab_name",  tabWidget()->tabText(i) );
00128         tabbed_area.appendChild( element );
00129     }
00130 
00131     QDomElement current_plotmatrix =  doc.createElement( "currentPlotMatrix" );
00132     current_plotmatrix.setAttribute( "index", tabWidget()->currentIndex() );
00133     tabbed_area.appendChild( current_plotmatrix );
00134 
00135     return tabbed_area;
00136 }
00137 
00138 bool TabbedPlotWidget::xmlLoadState(QDomElement &tabbed_area)
00139 {
00140     int num_tabs =  tabWidget()->count();
00141     int index = 0;
00142 
00143     QDomElement plotmatrix_el;
00144 
00145     for (  plotmatrix_el = tabbed_area.firstChildElement( "plotmatrix" )  ;
00146            !plotmatrix_el.isNull();
00147            plotmatrix_el = plotmatrix_el.nextSiblingElement( "plotmatrix" ) )
00148     {
00149         // add if tabs are too few
00150         if( index == num_tabs)
00151         {
00152             this->addTab( NULL );
00153             num_tabs++;
00154         }
00155         PlotMatrix* plot_matrix = static_cast<PlotMatrix*>(  tabWidget()->widget(index) );
00156         bool success = plot_matrix->xmlLoadState( plotmatrix_el );
00157 
00158         // read tab name
00159         if( plotmatrix_el.hasAttribute("tab_name"))
00160         {
00161             QString tab_name = plotmatrix_el.attribute("tab_name" );
00162             tabWidget()->setTabText( index, tab_name );
00163             plot_matrix->setName( tab_name );
00164         }
00165 
00166         if( !success )
00167         {
00168             return false;
00169         }
00170 
00171         index++;
00172     }
00173 
00174     // remove if tabs are too much
00175     while( num_tabs > index ){
00176         tabWidget()->removeTab( num_tabs-1 );
00177         num_tabs--;
00178     }
00179 
00180     QDomElement current_plotmatrix =  tabbed_area.firstChildElement( "currentPlotMatrix" );
00181     int current_index = current_plotmatrix.attribute( "index" ).toInt();
00182 
00183     if(current_index>=0 && current_index < tabWidget()->count())
00184     {
00185         tabWidget()->setCurrentIndex( current_index );
00186     }
00187     return true;
00188 }
00189 
00190 void TabbedPlotWidget::setStreamingMode(bool streaming_mode)
00191 {
00192     ui->buttonLinkHorizontalScale->setEnabled( !streaming_mode );
00193     ui->pushVerticalResize->setEnabled( !streaming_mode );
00194     ui->pushHorizontalResize->setEnabled( !streaming_mode );
00195 }
00196 
00197 
00198 TabbedPlotWidget::~TabbedPlotWidget(){
00199 
00200     delete ui;
00201 }
00202 
00203 void TabbedPlotWidget::on_renameCurrentTab()
00204 {
00205     int idx = tabWidget()->tabBar()->currentIndex ();
00206 
00207     bool ok = true;
00208     QString newName = QInputDialog::getText (
00209                 this, tr ("Change Name of the selected tab"),
00210                 tr ("Insert New Tab Name"),
00211                 QLineEdit::Normal,
00212                 tabWidget()->tabText (idx),
00213                 &ok);
00214 
00215     if (ok) {
00216         tabWidget()->setTabText (idx, newName);
00217         currentTab()->setName( newName );
00218     }
00219 }
00220 
00221 void TabbedPlotWidget::on_savePlotsToFile()
00222 {
00223     int idx = tabWidget()->tabBar()->currentIndex();
00224     PlotMatrix* matrix = static_cast<PlotMatrix*>( tabWidget()->widget(idx) );
00225 
00226     QFileDialog saveDialog;
00227     saveDialog.setAcceptMode(QFileDialog::AcceptSave);
00228     saveDialog.setDefaultSuffix("png");
00229     saveDialog.selectFile(currentTab()->name());
00230 
00231     saveDialog.setNameFilter("Compatible formats (*.jpg *.jpeg *.png)");
00232 
00233     saveDialog.exec();
00234 
00235     if(saveDialog.result() == QDialog::Accepted && !saveDialog.selectedFiles().empty())
00236     {
00237         QString fileName = saveDialog.selectedFiles().first();
00238 
00239         saveTabImage(fileName, matrix);
00240     }
00241 }
00242 
00243 void TabbedPlotWidget::saveTabImage(QString fileName, PlotMatrix* matrix)
00244 {
00245     QPixmap pixmap (1200,900);
00246     QPainter * painter = new QPainter(&pixmap);
00247 
00248     if ( !fileName.isEmpty() )
00249     {
00250         QwtPlotRenderer rend;
00251 
00252         int delta_X = pixmap.width() /  matrix->colsCount();
00253         int delta_Y = pixmap.height() /  matrix->rowsCount();
00254 
00255         for (unsigned c=0; c< matrix->colsCount(); c++)
00256         {
00257             for (unsigned r=0; r< matrix->rowsCount(); r++)
00258             {
00259                 PlotWidget* widget = matrix->plotAt(r,c);
00260                 QRect rect(delta_X*c, delta_Y*r, delta_X, delta_Y);
00261                 rend.render(widget,painter, rect);
00262             }
00263         }
00264         pixmap.save(fileName);
00265     }
00266 }
00267 
00268 void TabbedPlotWidget::on_pushAddRow_pressed()
00269 {
00270     currentTab()->addRow();
00271     onLabelStatusChanged();
00272     emit undoableChangeHappened();
00273 }
00274 
00275 void TabbedPlotWidget::on_pushAddColumn_pressed()
00276 {
00277     currentTab()->addColumn();
00278     onLabelStatusChanged();
00279     emit undoableChangeHappened();
00280 }
00281 
00282 void TabbedPlotWidget::on_pushVerticalResize_pressed()
00283 {
00284     currentTab()->maximumZoomOutVertical();
00285     emit undoableChangeHappened();
00286 }
00287 
00288 void TabbedPlotWidget::on_pushHorizontalResize_pressed()
00289 {
00290     currentTab()->maximumZoomOutHorizontal();
00291     emit undoableChangeHappened();
00292 }
00293 
00294 void TabbedPlotWidget::on_pushButtonZoomMax_pressed()
00295 {
00296     currentTab()->maximumZoomOut();
00297     emit undoableChangeHappened();
00298 }
00299 
00300 void TabbedPlotWidget::onMoveWidgetIntoNewTab(QString plot_name)
00301 {
00302     int src_row, src_col;
00303     PlotMatrix* src_matrix = nullptr;
00304     PlotWidget* source = nullptr;
00305 
00306     auto func = [&](QTabWidget * tabs)
00307     {
00308         for (int t=0; t < tabs->count(); t++)
00309         {
00310             PlotMatrix* matrix =  static_cast<PlotMatrix*>(tabs->widget(t));
00311 
00312             for(unsigned row=0; row< matrix->rowsCount(); row++)
00313             {
00314                 for(unsigned col=0; col< matrix->colsCount(); col++)
00315                 {
00316                     PlotWidget* plot = matrix->plotAt(row, col);
00317                     if( plot->windowTitle() == plot_name)
00318                     {
00319                         src_matrix = matrix;
00320                         src_row = row;
00321                         src_col = col;
00322                         source = plot;
00323                         return;
00324                     }
00325                 }
00326             }
00327         }
00328     };
00329 
00330     for(const auto& it: TabbedPlotWidget::instances())
00331     {
00332         func( it.second->tabWidget() );
00333     }
00334 
00335     addTab();
00336     PlotMatrix* dst_matrix  = currentTab();
00337     PlotWidget* destination = dst_matrix->plotAt(0,0);
00338 
00339     src_matrix->gridLayout()->removeWidget( source );
00340     dst_matrix->gridLayout()->removeWidget( destination );
00341 
00342     src_matrix->gridLayout()->addWidget( destination, src_row, src_col );
00343     dst_matrix->gridLayout()->addWidget( source,      0, 0 );
00344     source->changeBackgroundColor( Qt::white );
00345     destination->changeBackgroundColor( Qt::white );
00346 
00347     src_matrix->removeEmpty();
00348     src_matrix->updateLayout();
00349     dst_matrix->updateLayout();
00350     emit undoableChangeHappened();
00351 
00352 }
00353 
00354 void TabbedPlotWidget::on_addTabButton_pressed()
00355 {
00356     addTab( nullptr );
00357     emit undoableChangeHappened();
00358 }
00359 
00360 void TabbedPlotWidget::on_pushRemoveEmpty_pressed()
00361 {
00362     currentTab()->removeEmpty();
00363     emit undoableChangeHappened();
00364 }
00365 
00366 void TabbedPlotWidget::on_tabWidget_currentChanged(int index)
00367 {
00368     if( tabWidget()->count() == 0)
00369     {
00370         if( _parent_type.compare("main_window") == 0)
00371         {
00372             addTab( NULL);
00373         }
00374         else{
00375             this->parent()->deleteLater();
00376         }
00377     }
00378 
00379     PlotMatrix* tab = static_cast<PlotMatrix*>( tabWidget()->widget(index) );
00380     if( tab )
00381     {
00382         tab->replot();
00383     }
00384 }
00385 
00386 void TabbedPlotWidget::on_tabWidget_tabCloseRequested(int index)
00387 {
00388     PlotMatrix* tab = static_cast<PlotMatrix*>( tabWidget()->widget(index) );
00389 
00390     bool close_confirmed = true;
00391     if( tab->plotCount() == 1 )
00392     {
00393         if( tab->plotAt(0)->isEmpty()){
00394             close_confirmed = false;
00395         }
00396     }
00397 
00398     QMessageBox::StandardButton do_remove = QMessageBox::Yes;
00399 
00400     if( close_confirmed )
00401     {
00402         tabWidget()->setCurrentIndex( index );
00403         QApplication::processEvents();
00404 
00405         do_remove = QMessageBox::question( this, tr("Warning"),
00406                                           tr("Do you really want to destroy this tab?\n"),
00407                                           QMessageBox::Yes | QMessageBox::No,
00408                                           QMessageBox::No );
00409     }
00410     if( do_remove == QMessageBox::Yes )
00411     {
00412         // first add then delete.
00413         // Otherwise currentPlotGrid might be empty
00414         if( tabWidget()->count() == 1){
00415             on_addTabButton_pressed();
00416         }
00417 
00418         PlotMatrix* matrix = static_cast<PlotMatrix*>( tabWidget()->widget(index) );
00419 
00420         for(unsigned p=0; p< matrix->plotCount(); p++)
00421         {
00422             PlotWidget* plot = matrix->plotAt(p);
00423             plot->detachAllCurves();
00424             plot->deleteLater();
00425         }
00426 
00427         tabWidget()->removeTab( index );
00428         emit undoableChangeHappened();
00429     }
00430 }
00431 
00432 void TabbedPlotWidget::on_buttonLinkHorizontalScale_toggled(bool checked)
00433 {
00434     _horizontal_link = checked;
00435 
00436     for (int i = 0; i < tabWidget()->count(); i++)
00437     {
00438         PlotMatrix* tab = static_cast<PlotMatrix*>( tabWidget()->widget(i) );
00439         tab->setHorizontalLink( _horizontal_link );
00440     }
00441 }
00442 
00443 void TabbedPlotWidget::on_requestTabMovement(const QString & destination_name)
00444 {
00445     TabbedPlotWidget* destination_widget = TabbedPlotWidget::_instances[destination_name];
00446 
00447     PlotMatrix* tab_to_move = currentTab();
00448     int index = tabWidget()->tabBar()->currentIndex ();
00449 
00450     const QString& tab_name =  this->tabWidget()->tabText(index);
00451 
00452     destination_widget->tabWidget()->addTab( tab_to_move, tab_name );
00453 
00454     qDebug() << "move "<< tab_name<< " into " << destination_name;
00455     emit undoableChangeHappened();
00456 }
00457 
00458 void TabbedPlotWidget::on_moveTabIntoNewWindow()
00459 {
00460     emit sendTabToNewWindow( currentTab() );
00461 }
00462 
00463 void TabbedPlotWidget::on_pushButtonShowLabel_pressed()
00464 {
00465     switch(_labels_status)
00466     {
00467     case LabelStatus::LEFT:  _labels_status = LabelStatus::HIDDEN;  break;
00468     case LabelStatus::RIGHT: _labels_status = LabelStatus::LEFT;  break;
00469     case LabelStatus::HIDDEN: _labels_status = LabelStatus::RIGHT;  break;
00470     }
00471     onLabelStatusChanged( );
00472 }
00473 
00474 
00475 bool TabbedPlotWidget::eventFilter(QObject *obj, QEvent *event)
00476 {
00477     QTabBar* tab_bar = tabWidget()->tabBar();
00478 
00479     if (obj == tab_bar )
00480     {
00481         if( event->type() == QEvent::MouseButtonPress)
00482         {
00483             QMouseEvent *mouse_event = static_cast<QMouseEvent*>(event);
00484 
00485             int index = tab_bar->tabAt( mouse_event->pos() );
00486             tab_bar->setCurrentIndex( index );
00487 
00488 
00489             if( mouse_event->button() == Qt::RightButton )
00490             {
00491                 QMenu* submenu = new QMenu("Move tab to...");
00492                 _tab_menu->addMenu( submenu );
00493 
00494                 std::map<QString,TabbedPlotWidget*>::iterator it;
00495                 QSignalMapper* signalMapper = new QSignalMapper(submenu);
00496 
00497                 //-----------------------------------
00498                 QAction* action_new_window = submenu->addAction( "New Window" );
00499 
00500                 QIcon icon;
00501                 icon.addFile(QStringLiteral(":/icons/resources/light/stacks.png"), QSize(16, 16));
00502 
00503                 action_new_window->setIcon( icon);
00504                 submenu->addSeparator();
00505 
00506                 connect( action_new_window, &QAction::triggered, this, &TabbedPlotWidget::on_moveTabIntoNewWindow );
00507 
00508                 //-----------------------------------
00509                 for(auto& it : TabbedPlotWidget::_instances)
00510                 {
00511                     QString name = it.first;
00512                     TabbedPlotWidget* tabbed_menu = it.second;
00513                     if( tabbed_menu != this )
00514                     {
00515                         QAction* action = submenu->addAction( name );
00516                         connect(action, SIGNAL(triggered()), signalMapper, SLOT(map()));
00517                         signalMapper->setMapping( action, name );
00518                     }
00519                 }
00520 
00521                 connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(on_requestTabMovement(QString)) );
00522 
00523                 //-------------------------------
00524                 _tab_menu->exec( mouse_event->globalPos() );
00525                 //-------------------------------
00526                 submenu->deleteLater();
00527             }
00528         }
00529     }
00530 
00531     // Standard event processing
00532     return QObject::eventFilter(obj, event);
00533 }
00534 
00535 void TabbedPlotWidget::onLabelStatusChanged()
00536 {    
00537     for(int i=0; i< tabWidget()->count(); i++)
00538     {
00539         PlotMatrix* matrix = static_cast<PlotMatrix*>( tabWidget()->widget(i) );
00540 
00541         for(unsigned p=0; p< matrix->plotCount(); p++)
00542         {
00543             PlotWidget* plot = matrix->plotAt(p);
00544 
00545             plot->activateLegend( _labels_status != LabelStatus::HIDDEN );
00546             if(  _labels_status == LabelStatus::LEFT)
00547             {
00548                 plot->setLegendAlignment( Qt::AlignLeft );
00549             }
00550             else  if(  _labels_status == LabelStatus::RIGHT)
00551             {
00552                 plot->setLegendAlignment( Qt::AlignRight);
00553             }
00554             plot->replot();
00555         }
00556     }
00557 }
00558 
00559 void TabbedPlotWidget::closeEvent(QCloseEvent *event)
00560 {
00561   TabbedPlotWidget::_instances.erase(name());
00562 }
00563 
00564 const std::map<QString, TabbedPlotWidget *> &TabbedPlotWidget::instances()
00565 {
00566     return TabbedPlotWidget::_instances;
00567 }
00568 
00569 TabbedPlotWidget* TabbedPlotWidget::instance(const QString &key)
00570 {
00571     auto it = TabbedPlotWidget::_instances.find(key);
00572     if( it == TabbedPlotWidget::_instances.end())
00573     {
00574         return nullptr;
00575     }
00576     else{
00577         return it->second;
00578     }
00579 }
00580 
00581 void TabbedPlotWidget::setControlsVisible(bool visible)
00582 {
00583     ui->widgetControls->setVisible(visible);
00584 }
00585 
00586 
00587 


plotjuggler
Author(s): Davide Faconti
autogenerated on Wed Jul 3 2019 19:28:05