function_editor.cpp
Go to the documentation of this file.
00001 #include "function_editor.h"
00002 #include "custom_function.h"
00003 #include "plotwidget.h"
00004 #include <QDebug>
00005 #include <QMessageBox>
00006 #include <QFont>
00007 #include <QDomDocument>
00008 #include <QDomElement>
00009 #include <QFontDatabase>
00010 #include <QFile>
00011 #include <QMenu>
00012 #include <QAction>
00013 #include <QDir>
00014 #include <QFileDialog>
00015 #include <QFileInfo>
00016 #include <QSettings>
00017 #include <QByteArray>
00018 #include <QInputDialog>
00019 
00020 AddCustomPlotDialog::AddCustomPlotDialog(PlotDataMapRef &plotMapData,
00021                                      const CustomPlotMap &mapped_custom_plots,
00022                                      QWidget *parent) :
00023     QDialog(parent),
00024     _plot_map_data(plotMapData),
00025     _custom_plots(mapped_custom_plots),
00026     ui(new Ui::FunctionEditor),
00027     _v_count(1)
00028 {
00029     ui->setupUi(this);
00030 
00031     this->setWindowTitle("Create a custom timeseries");
00032     ui->mathEquation->setPlainText("return value*2");
00033 
00034     const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
00035     ui->globalVarsTextField->setFont(fixedFont);
00036     ui->mathEquation->setFont(fixedFont);
00037     ui->snippetTextEdit->setFont(fixedFont);
00038 
00039     QStringList numericPlotNames;
00040     for(const auto &p : _plot_map_data.numeric)
00041     {
00042         QString name = QString::fromStdString(p.first);
00043         numericPlotNames.push_back(name);
00044     }
00045     numericPlotNames.sort(Qt::CaseInsensitive);
00046     for(const QString& name : numericPlotNames)
00047     {
00048         ui->combo_linkedChannel->addItem(name);
00049         ui->curvesListWidget->addItem(name);
00050     }
00051 
00052     QSettings settings;
00053     QByteArray saved_xml = settings.value("AddCustomPlotDialog.savedXML", QByteArray() ).toByteArray();
00054     restoreGeometry(settings.value("AddCustomPlotDialog.geometry").toByteArray());
00055 
00056     if( saved_xml.isEmpty() )
00057     {
00058         QFile file("://resources/default.snippets.xml");
00059         if(!file.open(QIODevice::ReadOnly))
00060         {
00061             throw std::runtime_error( "problem with default.snippets.xml" );
00062         }
00063         saved_xml = file.readAll();
00064     }
00065 
00066     importSnippets(saved_xml);
00067 
00068     ui->snippetsListRecent->setContextMenuPolicy(Qt::CustomContextMenu);
00069 
00070     connect(ui->snippetsListRecent, &QListWidget::customContextMenuRequested,
00071             this,&AddCustomPlotDialog::recentContextMenu );
00072 
00073     ui->snippetsListSaved->setContextMenuPolicy(Qt::CustomContextMenu);
00074 
00075     connect(ui->snippetsListSaved, &QListWidget::customContextMenuRequested,
00076             this, &AddCustomPlotDialog::savedContextMenu );
00077 
00078     ui->splitter->setStretchFactor(0,3);
00079     ui->splitter->setStretchFactor(1,2);
00080 }
00081 
00082 AddCustomPlotDialog::~AddCustomPlotDialog()
00083 {
00084     QSettings settings;
00085     settings.setValue("AddCustomPlotDialog.savedXML", exportSnippets() );
00086     settings.setValue("AddCustomPlotDialog.geometry", saveGeometry());
00087     delete ui;
00088 }
00089 
00090 void AddCustomPlotDialog::setLinkedPlotName(const QString &linkedPlotName)
00091 {
00092     
00093     int idx = ui->combo_linkedChannel->findText(linkedPlotName);
00094     if (idx == -1)
00095     {
00096       idx = 0;
00097       ui->combo_linkedChannel->insertItem(idx, linkedPlotName);
00098     }
00099     ui->combo_linkedChannel->setCurrentIndex(idx);
00100 }
00101 
00102 void AddCustomPlotDialog::setEditorMode(EditorMode mode)
00103 {
00104     ui->label_linkeChannel->setVisible( mode != FUNCTION_ONLY );
00105     ui->combo_linkedChannel->setVisible( mode != FUNCTION_ONLY );
00106     ui->pushButtonCreate->setVisible( mode != FUNCTION_ONLY );
00107     ui->pushButtonSave->setVisible( mode != TIMESERIES_ONLY );
00108 }
00109 
00110 QString AddCustomPlotDialog::getLinkedData() const
00111 {
00112     return ui->combo_linkedChannel->currentText();
00113 }
00114 
00115 QString AddCustomPlotDialog::getGlobalVars() const
00116 {
00117     return ui->globalVarsTextField->toPlainText();
00118 }
00119 
00120 QString AddCustomPlotDialog::getEquation() const
00121 {
00122     return ui->mathEquation->toPlainText();
00123 }
00124 
00125 QString AddCustomPlotDialog::getName() const
00126 {
00127     return ui->nameLineEdit->text();
00128 }
00129 
00130 void AddCustomPlotDialog::editExistingPlot(CustomPlotPtr data)
00131 {
00132     ui->globalVarsTextField->setPlainText(data->globalVars());
00133     ui->mathEquation->setPlainText(data->function());
00134     setLinkedPlotName(QString::fromStdString(data->linkedPlotName()));
00135     ui->pushButtonCreate->setText("Update");
00136     ui->nameLineEdit->setText(QString::fromStdString(data->name()));
00137     ui->nameLineEdit->setEnabled(false);
00138 
00139     _is_new = false;
00140 }
00141 
00142 CustomPlotPtr AddCustomPlotDialog::getCustomPlotData() const
00143 {
00144     return _plot;
00145 }
00146 
00147 void AddCustomPlotDialog::on_curvesListWidget_doubleClicked(const QModelIndex &index)
00148 {
00149     QString appendString = QString("V%1 = $$%2$$\n")
00150             .arg(_v_count++)
00151             .arg(ui->curvesListWidget->item(index.row())->text());
00152 
00153     QPlainTextEdit* edit = ui->mathEquation;
00154 
00155     if(ui->globalVarsTextField->hasFocus())
00156     {
00157         edit = ui->globalVarsTextField;
00158     }
00159 
00160     if( !edit->toPlainText().endsWith("\n") )
00161     {
00162         edit->insertPlainText("\n");
00163     }
00164     edit->insertPlainText(appendString);
00165 }
00166 
00167 void AddCustomPlotDialog::importSnippets(const QByteArray& xml_text)
00168 {
00169     ui->snippetsListSaved->clear();
00170 
00171     _snipped_saved = GetSnippetsFromXML(xml_text);
00172 
00173     for(const auto &it : _snipped_saved)
00174     {
00175         ui->snippetsListSaved->addItem( it.first );
00176     }
00177 
00178     for( const auto& custom_it: _custom_plots)
00179     {
00180         const auto& math_plot = custom_it.second;
00181         SnippetData snippet;
00182         snippet.name = QString::fromStdString(math_plot->name());
00183 
00184         if( _snipped_saved.count( snippet.name ) > 0 )
00185         {
00186             continue;
00187         }
00188 
00189         snippet.globalVars = math_plot->globalVars();
00190         snippet.equation = math_plot->function();
00191         _snipped_recent.insert( {snippet.name, snippet } );
00192         ui->snippetsListRecent->addItem( snippet.name );
00193     }
00194     ui->snippetsListRecent->sortItems();
00195     ui->snippetsListSaved->sortItems();
00196 }
00197 
00198 QByteArray AddCustomPlotDialog::exportSnippets() const
00199 {
00200     QDomDocument doc;
00201     auto root = ExportSnippets( _snipped_saved, doc);
00202     doc.appendChild( root );
00203     return doc.toByteArray(2);
00204 }
00205 
00206 
00207 void AddCustomPlotDialog::on_snippetsListSaved_currentRowChanged(int current_row)
00208 {
00209     if( current_row < 0 )
00210     {
00211         ui->snippetTextEdit->setPlainText("");
00212         return;
00213     }
00214     const auto& name = ui->snippetsListSaved->currentItem()->text();
00215     const SnippetData& snippet = _snipped_saved.at(name);
00216     QString desc = QString("%1\n\nfunction calc(time,value)\n{\n%2\n}").arg(snippet.globalVars).arg(snippet.equation);
00217     ui->snippetTextEdit->setPlainText(desc);
00218 }
00219 
00220 void AddCustomPlotDialog::on_snippetsListSaved_doubleClicked(const QModelIndex &index)
00221 {
00222     const auto& name = ui->snippetsListSaved->item( index.row() )->text();
00223     const SnippetData& snippet = _snipped_saved.at(name);
00224 
00225     ui->globalVarsTextField->setPlainText(snippet.globalVars);
00226     ui->mathEquation->setPlainText(snippet.equation);
00227 }
00228 
00229 void AddCustomPlotDialog::on_snippetsListRecent_currentRowChanged(int current_row)
00230 {
00231     if( current_row < 0 )
00232     {
00233         ui->snippetTextEdit->setPlainText("");
00234         return;
00235     }
00236     const auto& name = ui->snippetsListRecent->currentItem()->text();
00237     const SnippetData& snippet = _snipped_recent.at(name);
00238 
00239     QString desc = QString("%1\n\nfunction calc(time,value)\n{\n%2\n}")
00240             .arg(snippet.globalVars)
00241             .arg(snippet.equation);
00242     ui->snippetTextEdit->setPlainText(desc);
00243 }
00244 
00245 void AddCustomPlotDialog::on_snippetsListRecent_doubleClicked(const QModelIndex &index)
00246 {
00247     const auto& name = ui->snippetsListRecent->item( index.row() )->text();
00248     const SnippetData& snippet = _snipped_recent.at(name);
00249 
00250     ui->globalVarsTextField->setPlainText(snippet.globalVars);
00251     ui->mathEquation->setPlainText(snippet.equation);
00252 }
00253 
00254 void AddCustomPlotDialog::recentContextMenu(const QPoint &pos)
00255 {
00256     auto list_recent = ui->snippetsListRecent;
00257 
00258     if( list_recent->selectedItems().size() != 1)
00259     {
00260         return;
00261     }
00262 
00263     auto list_saved = ui->snippetsListSaved;
00264 
00265     auto item = list_recent->selectedItems().first();
00266     const auto& name = item->text();
00267 
00268     QMenu menu;
00269     QAction* move_item = new QAction("Move to Saved", this);
00270     menu.addAction( move_item );
00271 
00272     connect(move_item, &QAction::triggered,
00273             this, [=]()
00274     {
00275         auto snippet_it = _snipped_recent.find(name);
00276 
00277         if( addToSaved( name, snippet_it->second ) )
00278         {
00279             _snipped_recent.erase( snippet_it );
00280             delete list_recent->takeItem( list_recent->row(item) );
00281         }
00282     });
00283 
00284     menu.exec( list_recent->mapToGlobal(pos) );
00285 }
00286 
00287 void AddCustomPlotDialog::savedContextMenu(const QPoint &pos)
00288 {
00289     auto list_saved = ui->snippetsListSaved;
00290 
00291     if( list_saved->selectedItems().size() != 1)
00292     {
00293         return;
00294     }
00295 
00296     QMenu menu;
00297 
00298     QAction* rename_item = new QAction("Rename...",  this);
00299     menu.addAction( rename_item );
00300 
00301     connect(rename_item, &QAction::triggered, this, &AddCustomPlotDialog::onRenameSaved);
00302 
00303     QAction* remove_item = new QAction("Remove",  this);
00304     menu.addAction( remove_item );
00305 
00306     connect(remove_item, &QAction::triggered,
00307             this, [list_saved, this]()
00308     {
00309         const auto& item = list_saved->selectedItems().first();
00310         _snipped_saved.erase( item->text() );
00311         delete list_saved->takeItem( list_saved->row(item) );
00312     });
00313 
00314     menu.exec( list_saved->mapToGlobal(pos) );
00315 }
00316 
00317 void AddCustomPlotDialog::on_nameLineEdit_textChanged(const QString &name)
00318 {
00319     ui->pushButtonCreate->setEnabled( !name.isEmpty() );
00320     ui->pushButtonSave->setEnabled(   !name.isEmpty() );
00321 
00322     if( _plot_map_data.numeric.count( name.toStdString() ) == 0)
00323     {
00324         ui->pushButtonCreate->setText("Create New Timeseries");
00325     }
00326     else{
00327         ui->pushButtonCreate->setText("Modify Timeseries");
00328     }
00329 }
00330 
00331 void AddCustomPlotDialog::on_buttonLoadFunctions_clicked()
00332 {
00333     QSettings settings;
00334     QString directory_path  = settings.value("AddCustomPlotDialog.loadDirectory",
00335                                              QDir::currentPath() ).toString();
00336 
00337     QString fileName = QFileDialog::getOpenFileName(this, tr("Open Snippet Library"),
00338                                                     directory_path,
00339                                                     tr("Snippets (*.snippets.xml)"));
00340     if (fileName.isEmpty()){
00341         return;
00342     }
00343 
00344     QFile file(fileName);
00345 
00346     if ( !file.open(QIODevice::ReadOnly)) {
00347         QMessageBox::critical(this, "Error", QString("Failed to open the file [%1]").arg(fileName) );
00348         return;
00349     }
00350 
00351     directory_path = QFileInfo(fileName).absolutePath();
00352     settings.setValue("AddCustomPlotDialog.loadDirectory", directory_path );
00353 
00354     importSnippets( file.readAll() );
00355 }
00356 
00357 void AddCustomPlotDialog::on_buttonSaveFunctions_clicked()
00358 {
00359     QSettings settings;
00360     QString directory_path  = settings.value("AddCustomPlotDialog.loadDirectory",
00361                                              QDir::currentPath() ).toString();
00362 
00363     QString fileName = QFileDialog::getSaveFileName(this, tr("Open Snippet Library"),
00364                                                     directory_path,
00365                                                     tr("Snippets (*.snippets.xml)"));
00366 
00367     if (fileName.isEmpty()){
00368         return;
00369     }
00370     if( !fileName.endsWith(".snippets.xml") )
00371     {
00372         fileName.append(".snippets.xml");
00373     }
00374 
00375     QFile file(fileName);
00376     if ( !file.open(QIODevice::WriteOnly)) {
00377         QMessageBox::critical(this, "Error", QString("Failed to open the file [%1]").arg(fileName));
00378         return;
00379     }
00380     auto data = exportSnippets();
00381 
00382     file.write(data);
00383     file.close();
00384 }
00385 
00386 void AddCustomPlotDialog::on_pushButtonSave_clicked()
00387 {
00388     QString name = ui->nameLineEdit->text();
00389 
00390     SnippetData snippet;
00391     snippet.name = name;
00392     snippet.globalVars = ui->globalVarsTextField->toPlainText();
00393     snippet.equation   = ui->mathEquation->toPlainText();
00394 
00395     addToSaved( name, snippet);
00396 
00397     on_snippetsListSaved_currentRowChanged( ui->snippetsListSaved->currentRow() );
00398 }
00399 
00400 bool AddCustomPlotDialog::addToSaved(const QString& name, const SnippetData& snippet)
00401 {
00402     if( _snipped_saved.count(name) )
00403     {
00404         QMessageBox msgBox(this);
00405         msgBox.setWindowTitle("Warning");
00406         msgBox.setText(tr("A function with the same name exists already in the list of saved functions.\n"));
00407         msgBox.addButton(QMessageBox::Cancel);
00408         QPushButton* button = msgBox.addButton(tr("Overwrite"), QMessageBox::YesRole);
00409         msgBox.setDefaultButton(button);
00410 
00411         int res = msgBox.exec();
00412 
00413         if( res < 0 ||  res == QMessageBox::Cancel) {
00414             return false;
00415         }
00416     }
00417     else{
00418         ui->snippetsListSaved->addItem(name);
00419         ui->snippetsListSaved->sortItems();
00420     }
00421     _snipped_saved[name] = snippet;
00422     return true;
00423 }
00424 
00425 void AddCustomPlotDialog::onRenameSaved()
00426 {
00427     auto list_saved = ui->snippetsListSaved;
00428     auto item = list_saved->selectedItems().first();
00429     const auto& name = item->text();
00430 
00431     bool ok;
00432     QString new_name = QInputDialog::getText(this, tr("Change the name of the function"),
00433                                          tr("New name:"), QLineEdit::Normal,
00434                                          name, &ok);
00435 
00436     if (!ok || new_name.isEmpty() || new_name == name)
00437     {
00438         return;
00439     }
00440 
00441     SnippetData snippet = _snipped_saved[ name ];
00442     _snipped_saved.erase( name );
00443     snippet.name = new_name;
00444 
00445     _snipped_saved.insert( {new_name, snippet} );
00446     item->setText( new_name );
00447     ui->snippetsListSaved->sortItems();
00448 }
00449 
00450 
00451 void AddCustomPlotDialog::on_pushButtonCreate_clicked()
00452 {
00453     try {
00454         std::string plotName = getName().toStdString();
00455 
00456         // check if name is unique (except if is custom_plot)
00457         if(_plot_map_data.numeric.count(plotName) != 0 &&
00458            _custom_plots.count(plotName) == 0 )
00459         {
00460             throw std::runtime_error("plot name already exists and can't be modified");
00461         }
00462 
00463         _plot = std::make_shared<CustomFunction>(getLinkedData().toStdString(),
00464                                            plotName,
00465                                            getGlobalVars(),
00466                                            getEquation());
00467         QDialog::accept();
00468     }
00469     catch (const std::runtime_error &e) {
00470         _plot.reset();
00471         QMessageBox::critical(this, "Error", "Failed to create math plot : "
00472                               + QString::fromStdString(e.what()));
00473         QDialog::reject();
00474     }
00475 }
00476 
00477 void AddCustomPlotDialog::on_lineEditFilter_textChanged(const QString &search_string)
00478 {
00479     QStringList spaced_items = search_string.split(' ');
00480 
00481     for (int row=0; row < ui->curvesListWidget->count(); row++)
00482     {
00483         auto item = ui->curvesListWidget->item(row);
00484         QString name = item->text();
00485         bool toHide = false;
00486 
00487         for (const auto& item: spaced_items)
00488         {
00489             if( !name.contains(item) )
00490             {
00491                 toHide = true;
00492                 break;
00493             }
00494         }
00495         ui->curvesListWidget->setRowHidden(row, toHide );
00496     }
00497 }


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