27 #include <QCoreApplication>
29 #include <QInputDialog>
31 #include <QMessageBox>
32 #include <QScrollArea>
36 #include <QVBoxLayout>
47 QDir::setCurrent(QCoreApplication::applicationDirPath());
52 setWindowTitle(tr(
"Control-Box RST"));
55 setWindowState(Qt::WindowMaximized);
61 _rpc_client = std::make_shared<MasterServiceClient>();
78 qRegisterMetaType<std::shared_ptr<MasterServiceClient>>(
"std::shared_ptr<MasterServiceClient>");
83 if (_rpc_client) _rpc_client = rpc_client;
86 corboMainWindow::~corboMainWindow()
88 _rpc_worker_thread.quit();
89 _rpc_worker_thread.wait();
92 void corboMainWindow::closeEvent(QCloseEvent* event) { writeWindowSettings(); }
94 void corboMainWindow::createActions()
97 _action_save_parameters_file =
new QAction(tr(
"Save Parameters..."),
this);
98 _action_save_parameters_file->setStatusTip(tr(
"Save current parameters to file."));
99 connect(_action_save_parameters_file, &QAction::triggered, _toolbox_widget,
100 [
this](
bool ) { _toolbox_widget->saveCurrentParametersToFile(); });
103 _action_load_parameters_file =
new QAction(tr(
"Load Parameters..."),
this);
104 _action_load_parameters_file->setStatusTip(tr(
"Load parameters from file."));
105 connect(_action_load_parameters_file, &QAction::triggered, _toolbox_widget,
106 [
this](
bool ) { _toolbox_widget->loadParametersFromFile(); });
109 _action_remove_signals =
new QAction(tr(
"Clear Signals"),
this);
110 _action_remove_signals->setStatusTip(tr(
"Clear all signals"));
111 connect(_action_remove_signals, &QAction::triggered, [
this](
bool ) {
112 _signal_helper->clearAll();
113 _toolbox_widget->getAvailableSignals();
117 _action_close_scopes =
new QAction(tr(
"Close Scopes"),
this);
118 _action_close_scopes->setStatusTip(tr(
"Clear all scopes"));
119 connect(_action_close_scopes, SIGNAL(triggered()), _scope_collection_widget, SLOT(closeAllScopes()));
122 _action_rescale_scope_axes =
new QAction(tr(
"Rescale Scope Axes"),
this);
123 connect(_action_rescale_scope_axes, &QAction::triggered, _scope_collection_widget, &ScopeCollectionWidget::resizeScopeAxes);
126 _action_default_layout =
new QAction(tr(
"Default Layout"),
this);
127 _action_default_layout->setStatusTip(tr(
"Set docks to its default position"));
128 connect(_action_default_layout, SIGNAL(triggered()),
this, SLOT(setDefaultLayout()));
131 _action_rpc_server_address =
new QAction(tr(
"Change Server Address..."),
this);
132 connect(_action_rpc_server_address, &QAction::triggered,
this, [
this](
bool ) {
134 QString
text = QInputDialog::getText(
this, tr(
"QInputDialog::getText()"), tr(
"Server Address:"), QLineEdit::Normal, _rpc_server_address, &
ok);
135 if (
ok && !
text.isEmpty())
137 _rpc_server_address =
text;
138 emit requestRpcServerAddress(_rpc_server_address);
143 _action_about =
new QAction(tr(
"About"),
this);
144 _action_about->setStatusTip(tr(
"Display general information about the program"));
145 connect(_action_about, SIGNAL(triggered()),
this, SLOT(aboutPopup()));
148 _action_exit_program =
new QAction(tr(
"Exit"),
this);
149 connect(_action_exit_program, SIGNAL(triggered()),
this, SLOT(close()));
152 for (std::size_t i = 0; i < _action_recent_files.size(); ++i)
154 _action_recent_files[i] =
new QAction(
this);
155 _action_recent_files[i]->setVisible(
false);
156 QAction* cur_action = _action_recent_files[i];
157 connect(_action_recent_files[i], &QAction::triggered, _toolbox_widget, [
this, cur_action]() {
158 if (cur_action) _toolbox_widget->loadParametersFromFile(cur_action->data().toString());
163 void corboMainWindow::createMenus()
166 _menu_file = menuBar()->addMenu(tr(
"File"));
169 _menu_parameters = menuBar()->addMenu(tr(
"Parameters"));
172 _menu_scopes = menuBar()->addMenu(tr(
"Scopes"));
175 _menu_signals = menuBar()->addMenu(tr(
"Signals"));
178 _menu_view = menuBar()->addMenu(tr(
"View"));
181 _menu_help = menuBar()->addMenu(tr(
"&Help"));
184 menuBar()->setNativeMenuBar(
false);
188 void corboMainWindow::createStatusBar() { displayStatusReady(); }
190 void corboMainWindow::createDockWindows()
193 QScrollArea* toolbox_scroll_area =
new QScrollArea;
194 _toolbox_widget =
new ToolboxWidget(_signal_helper, _rpc_client);
195 toolbox_scroll_area->setWidget(_toolbox_widget);
196 connect(_toolbox_widget, &ToolboxWidget::parameterSavedToFile,
this, &corboMainWindow::addToRecentFileAction);
197 connect(_toolbox_widget, &ToolboxWidget::parameterLoadedFromFile,
this, &corboMainWindow::addToRecentFileAction);
199 _dock_toolbox_widget =
new QDockWidget(tr(
"Toolbox"),
this);
200 _dock_toolbox_widget->setFloating(
false);
201 _dock_toolbox_widget->setObjectName(
"ToolboxDock");
202 _dock_toolbox_widget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
203 _dock_toolbox_widget->setWidget(_toolbox_widget);
204 _dock_toolbox_widget->setFeatures(QDockWidget::AllDockWidgetFeatures);
205 addDockWidget(Qt::LeftDockWidgetArea, _dock_toolbox_widget);
211 connect(_signal_helper.get(), &SignalHelper::newMeasurement, _scope_collection_widget, &ScopeCollectionWidget::addMeasurement);
212 connect(_signal_helper.get(), &SignalHelper::signalRemoved, _scope_collection_widget, &ScopeCollectionWidget::removeSignal);
213 connect(_signal_helper.get(), &SignalHelper::newSeries, _scope_collection_widget, &ScopeCollectionWidget::initializeTask);
215 _dock_scope_widget =
new QDockWidget(tr(
"Scopes"),
this);
216 _dock_scope_widget->setFloating(
false);
217 _dock_scope_widget->setObjectName(
"ScopesDock");
218 _dock_scope_widget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
221 _dock_scope_widget->setWidget(_scope_collection_widget);
222 _dock_scope_widget->setFeatures(QDockWidget::AllDockWidgetFeatures);
223 addDockWidget(Qt::RightDockWidgetArea, _dock_scope_widget);
226 QScrollArea* signal_scroll_area =
new QScrollArea;
231 connect(_signal_helper.get(), &SignalHelper::newSignal, _signal_collection_widget, &SignalCollectionWidget::addSignal);
232 connect(_signal_helper.get(), &SignalHelper::signalRemoved, _signal_collection_widget, &SignalCollectionWidget::removeTreeItem);
233 connect(_toolbox_widget, &ToolboxWidget::taskCompleted, _signal_collection_widget, &SignalCollectionWidget::moveToRecent);
234 connect(_signal_collection_widget, &SignalCollectionWidget::requestTaskParameterBackup, _toolbox_widget, &ToolboxWidget::restoreTaskParameters);
235 connect(_signal_collection_widget, &SignalCollectionWidget::taskRemoved, _toolbox_widget, &ToolboxWidget::removeFromTaskCache);
237 signal_scroll_area->setWidget(_signal_collection_widget);
238 signal_scroll_area->setWidgetResizable(
true);
240 _dock_signal_widget =
new QDockWidget(tr(
"Signals"),
this);
241 _dock_signal_widget->setFloating(
false);
242 _dock_signal_widget->setObjectName(
"SignalsDock");
243 _dock_signal_widget->setAllowedAreas(Qt::AllDockWidgetAreas);
244 _dock_signal_widget->setWidget(signal_scroll_area);
245 _dock_signal_widget->setFeatures(QDockWidget::AllDockWidgetFeatures);
248 _toolbox_widget->getAvailableSignals();
249 _toolbox_widget->setSignalAutoRequest(
true);
252 void corboMainWindow::addMenuActions()
254 _menu_file->addAction(_action_rpc_server_address);
255 _menu_file->addSeparator();
256 _menu_file->addAction(_action_exit_program);
258 _menu_view->addAction(_action_default_layout);
260 _menu_parameters->addAction(_action_save_parameters_file);
261 _menu_parameters->addSeparator();
262 _menu_parameters->addAction(_action_load_parameters_file);
263 _menu_recent_parameters = _menu_parameters->addMenu(tr(
"Recent Parameters"));
264 for (std::size_t i = 0; i < _action_recent_files.size(); ++i) _menu_recent_parameters->addAction(_action_recent_files[i]);
265 updateRecentFileActions();
267 _menu_scopes->addAction(_action_rescale_scope_axes);
268 _menu_scopes->addAction(_action_close_scopes);
270 _menu_signals->addAction(_action_remove_signals);
272 _menu_help->addAction(_action_about);
275 void corboMainWindow::setDefaultLayout()
277 _dock_toolbox_widget->hide();
278 _dock_scope_widget->hide();
279 _dock_signal_widget->hide();
280 addDockWidget(Qt::LeftDockWidgetArea, _dock_toolbox_widget);
281 _dock_toolbox_widget->setFloating(
false);
282 _dock_toolbox_widget->show();
284 addDockWidget(Qt::RightDockWidgetArea, _dock_scope_widget);
285 _dock_scope_widget->setFloating(
false);
286 _dock_scope_widget->show();
288 addDockWidget(Qt::RightDockWidgetArea, _dock_signal_widget);
289 splitDockWidget(_dock_scope_widget, _dock_signal_widget,
Qt::Horizontal);
290 _dock_signal_widget->setFloating(
false);
291 _dock_signal_widget->show();
297 void corboMainWindow::readWindowSettings()
300 QVariant pos_var = settings.value(
"pos");
301 QVariant size_var = settings.value(
"size");
302 QVariant dock_var = settings.value(
"dock_locations");
303 QVariant rpc_server_address_var = settings.value(
"rpc_server_address");
305 if (pos_var.canConvert<QPoint>()) move(pos_var.toPoint());
306 if (size_var.canConvert<QSize>()) resize(size_var.toSize());
307 if (dock_var.canConvert<QByteArray>()) restoreState(dock_var.toByteArray());
308 if (rpc_server_address_var.canConvert<QString>()) _rpc_server_address = rpc_server_address_var.toString();
311 void corboMainWindow::writeWindowSettings()
314 settings.setValue(
"pos", pos());
315 settings.setValue(
"size",
size());
316 settings.setValue(
"dock_locations", saveState());
317 settings.setValue(
"rpc_server_address", _rpc_server_address);
320 void corboMainWindow::displayStatus(
const QString& status,
double duration_ms)
322 if (status.isEmpty())
324 displayStatusReady();
327 statusBar()->showMessage(status);
332 QTimer::singleShot(duration_ms,
this, SLOT(displayStatusReady()));
336 void corboMainWindow::updateRecentFileActions()
339 QStringList files = settings.value(
"recentFileList").toStringList();
341 int num_recent_files = qMin(files.size(), (
int)_action_recent_files.size());
343 for (
int i = 0; i < num_recent_files; ++i)
345 QString
text = files[i];
346 _action_recent_files[i]->setText(
text);
347 _action_recent_files[i]->setData(files[i]);
348 _action_recent_files[i]->setVisible(
true);
350 for (
int j = num_recent_files; j < (
int)_action_recent_files.size(); ++j) _action_recent_files[j]->setVisible(
false);
353 void corboMainWindow::addToRecentFileAction(
const QString&
filename)
356 QStringList files = settings.value(
"recentFileList").toStringList();
359 while (files.size() > _action_recent_files.size()) files.removeLast();
361 settings.setValue(
"recentFileList", files);
363 updateRecentFileActions();
366 void corboMainWindow::aboutPopup()
368 QMessageBox::about(
this, tr(
"About"), tr(
"<p><b>Institute of Control Theory and Systems Engineering, TU Dortmund University.</b></p>"
369 "<p>Written by Christoph Rösmann, <a "
370 "href=\"mailto:christoph.roesmann@tu-dortmund.de\">christoph.roesmann@tu-dortmund.de</a></p>"));
373 void corboMainWindow::configureRpcWorker()
375 displayStatus(
"trying to connect with rpc server at " + _rpc_server_address);
377 RpcConnectionWorker* rpc_worker =
new RpcConnectionWorker(_rpc_client);
378 rpc_worker->moveToThread(&_rpc_worker_thread);
379 connect(
this, SIGNAL(requestRpcServerAddress(
const QString&)), rpc_worker, SLOT(connectRpc(
const QString&)));
380 connect(&_rpc_worker_thread, SIGNAL(finished()), rpc_worker, SLOT(deleteLater()));
381 connect(rpc_worker, SIGNAL(connectionResult(std::shared_ptr<MasterServiceClient>)),
this,
382 SLOT(updatedRpcClient(std::shared_ptr<MasterServiceClient>)));
383 connect(rpc_worker, &RpcConnectionWorker::connectionResult,
this,
384 [
this](std::shared_ptr<MasterServiceClient> ) { displayStatusReady(); });
386 _rpc_worker_thread.start(QThread::LowPriority);
388 emit requestRpcServerAddress(_rpc_server_address);
391 void corboMainWindow::updatedRpcClient(std::shared_ptr<MasterServiceClient> client)
397 _toolbox_widget->requestParametersFromService();