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