29 #include <QFileDialog>
30 #include <QMessageBox>
39 : QWidget(parent), _signal_helper(signal_helper), _rpc_client(rpc)
41 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
43 if (rpc) _param_message = rpc->createParameterMsg();
45 createToolboxContent();
48 qRegisterMetaType<messages::Signal>(
"messages::Signal");
51 ToolboxWidget::~ToolboxWidget()
53 _rpc_task_thread.quit();
54 _rpc_task_thread.wait();
57 QSize ToolboxWidget::sizeHint()
const {
return QSize(350, 800); }
59 void ToolboxWidget::createToolboxContent()
61 QVBoxLayout* layout =
new QVBoxLayout(
this);
63 layout->setAlignment(Qt::AlignTop);
65 _toolbox =
new QToolBox;
69 initializeToolboxes();
71 layout->addWidget(_toolbox);
74 layout->addSpacing(20);
75 QFrame* hline =
new QFrame;
76 hline->setFrameShape(QFrame::HLine);
77 hline->setFrameShadow(QFrame::Sunken);
78 hline->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
79 layout->addWidget(hline);
81 layout->addSpacing(20);
83 QHBoxLayout* btn_layout =
new QHBoxLayout;
84 _btn_perform_task =
new QPushButton(_task_button_label_active);
85 _btn_perform_task->setMaximumWidth(200);
86 _btn_perform_task->setMaximumHeight(40);
87 connect(_btn_perform_task, &QPushButton::clicked, [
this](
bool) { performTask(); });
88 btn_layout->addWidget(_btn_perform_task);
89 layout->addLayout(btn_layout);
94 void ToolboxWidget::initializeToolboxes()
96 if (!_param_message)
return;
98 if (!_param_widgets.empty())
104 namespace p = google::protobuf;
105 const p::Descriptor* desc = _param_message->GetDescriptor();
106 int num_fields = desc->field_count();
107 for (
int i = 0; i < num_fields; ++i)
109 const p::FieldDescriptor* field = desc->field(i);
110 if (field->cpp_type() != p::FieldDescriptor::CPPTYPE_MESSAGE)
113 "ToolboxWidget::createToolboxContent(): non-message-field found in parameter message. Only message fields are allowed in top-level");
117 QString name = QString::fromStdString(field->name());
118 name[0] = name[0].toUpper();
121 _toolbox->addItem(param_widget, name);
122 connect(param_widget, &ParameterWidget::updatedOneOfField, [
this](
const QString& ) {
123 if (_signal_auto_update) getAvailableSignals();
125 connect(param_widget, &ParameterWidget::signalUpdateRequested,
this, &ToolboxWidget::getAvailableSignals);
128 _param_widgets.push_back(param_widget);
132 void ToolboxWidget::updateParameterWidgets()
134 namespace p = google::protobuf;
135 const p::Descriptor* desc = _param_message->GetDescriptor();
136 int num_fields = desc->field_count();
138 if (num_fields != _param_widgets.size())
140 PRINT_ERROR(
"ToolboxWidget::updateParameterWidgets(): Number of fields does not match number of ParameterWidgets.");
144 _signal_auto_update =
false;
146 for (
int i = 0; i < num_fields; ++i)
148 const p::FieldDescriptor* field = desc->field(i);
150 if (field->cpp_type() != p::FieldDescriptor::CPPTYPE_MESSAGE)
152 PRINT_ERROR(
"ToolboxWidget::fromMessage(): non-message-field found in parameter message. Only message fields are allowed in top-level");
155 _param_widgets[i]->generateFromAllocatedField(_param_message.get(), field);
158 _signal_auto_update =
true;
161 getAvailableSignals();
164 void ToolboxWidget::requestParametersFromService()
172 if (_rpc_client->getParameters(*_param_message))
174 updateParameterWidgets();
178 bool ToolboxWidget::sendParametersToService(
bool suppress_warning)
185 status +=
"Cannot connect to RPC client / connection lost\n";
186 if (!suppress_warning) QMessageBox::warning(
this, tr(
"RPC Connection Error"), status);
191 if (_rpc_client->setParameters(*_param_message, status_msg))
193 if (!status_msg.ok())
195 status += QString::fromStdString(status_msg.text()) +
"\n";
200 if (ret_val ==
false && !suppress_warning) QMessageBox::warning(
this, tr(
"Invalid Configuration"), status);
204 void ToolboxWidget::performTask()
206 if (!_rpc_client)
return;
210 if (_rpc_client->stopTask()) setTaskRunningFlag(
false);
215 if (!sendParametersToService())
return;
218 setTaskRunningFlag(
true);
222 rpc_worker->moveToThread(&_rpc_task_thread);
223 connect(&_rpc_task_thread, SIGNAL(started()), rpc_worker, SLOT(performTask()));
224 connect(rpc_worker, &RpcTaskWorker::feedback,
this, [
this](
const messages::Signal& signal) { _signal_helper->addSignal(signal); });
225 connect(rpc_worker, SIGNAL(taskFinished(
bool,
const QString&)),
this, SLOT(rpcTaskFinished(
bool,
const QString&)));
226 connect(&_rpc_task_thread, SIGNAL(finished()), rpc_worker, SLOT(deleteLater()));
228 _rpc_task_thread.start(QThread::NormalPriority);
231 void ToolboxWidget::rpcTaskFinished(
bool success,
const QString& msg)
233 setTaskRunningFlag(
false);
235 _rpc_task_thread.quit();
239 emit taskCompleted(QDateTime::currentDateTime());
244 _task_cache.toCache(std::to_string(_signal_helper->currentSeriesId()), *_param_message);
248 _signal_helper->startNewSeries();
252 QMessageBox::warning(
this, tr(
"Something went wrong..."), msg);
257 if (_signal_auto_update) getAvailableSignals();
260 void ToolboxWidget::getAvailableSignals()
262 if (!_signal_auto_update)
return;
264 if (!_rpc_client)
return;
267 sendParametersToService(
true);
270 _signal_helper->clearCurrentSeries();
272 auto signal_feedback = [
this](
const messages::Signal& signal) { _signal_helper->addSignal(signal); };
273 _rpc_client->getAvailableSignals(signal_feedback);
276 void ToolboxWidget::restoreTaskParameters(
int task_id)
278 std::unique_ptr<google::protobuf::Message> cached_msg = _task_cache.fromCache(std::to_string(task_id));
281 fromMessage(*cached_msg);
285 void ToolboxWidget::removeFromTaskCache(
int task_id) { _task_cache.erase(std::to_string(task_id)); }
287 void ToolboxWidget::saveCurrentParametersToFile()
289 if (!_param_message)
return;
290 saveParametersToFile(*_param_message);
293 void ToolboxWidget::saveParametersToFile(
int task_id)
295 std::unique_ptr<google::protobuf::Message> cached_msg = _task_cache.fromCache(std::to_string(task_id));
297 saveParametersToFile(*cached_msg);
299 QMessageBox::warning(
this,
"Warning",
"Cannot save parameters to file, since not found in cache.");
302 void ToolboxWidget::saveParametersToFile(
const google::protobuf::Message& params)
304 QString default_filter = tr(
"Parameter file (*.cparams)");
306 QString
filename = QFileDialog::getSaveFileName(
this, tr(
"Export Parameters"),
"parameters.cparams",
307 tr(
"Parameter file (*.cparams);;All files (*.*)"), &default_filter);
310 QFileDialog::getSaveFileName(
this, tr(
"Export Parameters"),
"parameters", tr(
"Parameter file (*.cparams);;All files (*.*)"), &default_filter);
315 std::ofstream file(
filename.toStdString(), std::ofstream::binary | std::ofstream::trunc);
319 QMessageBox::warning(
this,
"Warning",
"Cannot open file with write-permissions for exporting parameters.");
322 params.SerializeToOstream(&file);
324 emit parameterSavedToFile(
filename);
327 void ToolboxWidget::loadParametersFromFile()
329 QString default_filter = tr(
"Parameter file (*.cparams)");
331 QFileDialog::getOpenFileName(
this, tr(
"Import Parameters"),
"parameters", tr(
"Parameter file (*.cparams);;All files (*.*)"), &default_filter);
335 void ToolboxWidget::loadParametersFromFile(
const QString& filepath)
339 QMessageBox::warning(
this,
"Warning",
"Cannot load parameter before RPC client is configured.");
343 if (filepath.isEmpty())
return;
345 std::ifstream file(filepath.toStdString());
349 QMessageBox::warning(
this,
"Warning",
"Cannot open file with read-permissions for importing parameters.");
353 _param_message->Clear();
354 if (_param_message->ParsePartialFromIstream(&file))
356 updateParameterWidgets();
357 emit parameterLoadedFromFile(filepath);
361 void ToolboxWidget::clearParameters()
363 for (ParameterWidget* param_widget : _param_widgets) param_widget->clearElements();
366 void ToolboxWidget::setRpcClient(std::shared_ptr<MasterServiceClient> rpc_client)
368 _rpc_client = rpc_client;
371 _param_message = rpc_client->createParameterMsg();
372 initializeToolboxes();
373 requestParametersFromService();
377 void ToolboxWidget::fromMessage(
const google::protobuf::Message& parameters)
379 if (!_param_message)
return;
381 _param_message->CopyFrom(parameters);
382 updateParameterWidgets();
385 void ToolboxWidget::toMessage(google::protobuf::Message& parameters)
const
387 if (!_param_message)
return;
389 parameters.CopyFrom(*_param_message);
392 void ToolboxWidget::setTaskRunningFlag(
bool running)
394 _task_running = running;
396 _btn_perform_task->setText(_task_button_label_inactive);
398 _btn_perform_task->setText(_task_button_label_active);