ImageProviderConfigWidget.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package VisionX::gui-plugins::ImageRecorder
19 * @author Christian R. G. Dreher <c.dreher@kit.edu>
20 * @date 2020
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
25
27
28
29// Qt
30#include <QIcon>
31#include <QProgressBar>
32
33// Simox
34#include <SimoxUtility/algorithm/string/string_tools.h>
35
36// ArmarX
38
41
42namespace
43{
44 struct Progress
45 {
46 int min;
47 int max;
48 int val;
49 };
50
51 const Progress invalid_progress{0, 1, -1};
52 const Progress indefinite_progress{0, 0, 0};
53
54 void
55 set_progress(QProgressBar* progress_bar, const Progress& progress)
56 {
57 progress_bar->setMinimum(progress.min);
58 progress_bar->setMaximum(progress.max);
59 progress_bar->setValue(progress.val);
60 }
61} // namespace
62
64 QWidget* parent,
66 const std::string& image_provider_name,
67 const visionx::imrec::ChannelConfigs& channel_configs) :
68 QWidget(parent), m_iceman{iceman}, m_image_provider_name{image_provider_name}
69{
70 m_widget.setupUi(this);
71 connect(this,
73 this,
74 &ImageProviderConfigWidget::state_changed);
75 connect(m_widget.remove_image_provider,
76 &QPushButton::clicked,
77 this,
78 &ImageProviderConfigWidget::image_provider_removed);
79
80 const QString q_image_provider_name = QString::fromStdString(m_image_provider_name);
81 m_widget.configs->setTitle(QString{"Image provider: "} + q_image_provider_name);
82
83 // Replace or remove dummy values from the UI designer.
84 set_progress(m_widget.write_progress, ::invalid_progress);
85 m_widget.ice_proxy_finder_placeholder->deleteLater(); // Remove placeholder.
86
87 // Timer for blink animation while recording/writing.
88 m_blink_timer = new QTimer(this);
89 m_blink_timer->setSingleShot(false);
90 m_blink_timer->setInterval(750);
91 connect(m_blink_timer, &QTimer::timeout, this, &ImageProviderConfigWidget::blink);
92
93 // Ice proxy finder to select a recording image provider.
95 m_widget.ice_proxy_finder->layout()->addWidget(m_ice_proxy_finder);
96 m_ice_proxy_finder->setIceManager(iceman);
97 m_ice_proxy_finder->setDefaultSelectedProxyAsItem(q_image_provider_name);
98 m_ice_proxy_finder->setSearchMask("*");
99 connect(m_ice_proxy_finder->getProxyNameComboBox(),
100 SIGNAL(editTextChanged(QString)),
101 this,
102 SLOT(image_provider_renamed(QString)));
103
104 // Initialise UI according to channel settings and channel preferences.
105 std::vector<imrec::ChannelPreferences> channel_prefs_list;
106 std::vector<imrec::ChannelPreferences> reported_channel_prefs_list = get_channel_prefs();
107 const bool use_default_channel_prefs =
108 reported_channel_prefs_list.size() != channel_configs.size();
109 for (unsigned int i = 0; i < channel_configs.size(); ++i)
110 {
111 imrec::ChannelPreferences channel_prefs;
112 if (use_default_channel_prefs)
113 {
114 channel_prefs.name = "c" + std::to_string(i);
115 channel_prefs.requiresLossless = false;
116 }
117 else
118 {
119 channel_prefs = reported_channel_prefs_list.at(i);
120 }
121 channel_prefs_list.push_back(channel_prefs);
122 }
123
124 build_ui_from_configs(channel_configs, channel_prefs_list);
125}
126
130
131void
133{
134 m_widget.configs->setTitle(QString::fromStdString("Image provider: " + new_name));
135 m_ice_proxy_finder->setDefaultSelectedProxyAsItem(QString::fromStdString(new_name));
136 m_image_provider_name = new_name;
137 update_channel_list();
138}
139
140void
142{
143 // TODO: Display fancy graphics.
144 ARMARX_WARNING << "Invalid name '" << new_name << "' for image provider (already taken).";
145}
146
147std::vector<visionx::imrec::ChannelConfig>
149{
150 const bool disabled = false /*not m_widget.configs->isChecked()*/;
151 std::vector<visionx::imrec::ChannelConfig> ccs;
152 std::transform(m_channel_config_widgets.begin(),
153 m_channel_config_widgets.end(),
154 std::back_inserter(ccs),
155 [&](const auto* ccw) { return ccw->toChannelConfig(disabled); });
156 return ccs;
157}
158
159void
161 std::optional<visionx::imrec::Status> status)
162{
163 const std::optional<imrec::State> old_state = m_current_state;
164 std::optional<imrec::State> new_state;
165 if (status.has_value())
166 {
167 new_state = status.value().type;
168 }
169
170 Progress progress;
171
172 if (status.has_value() and status.value().type != imrec::State::offline)
173 {
174 const imrec::Status s = status.value();
175
176 if (s.type == imrec::State::ready and s.framesWritten == 0 and s.framesBuffered == 0)
177 {
178 progress = ::invalid_progress;
179 }
180 else if (s.type == imrec::State::scheduled)
181 {
182 progress = ::indefinite_progress;
183 }
184 else
185 {
186 progress.min = 0;
187 progress.max = s.framesWritten + s.framesBuffered;
188 progress.val = s.framesWritten;
189 }
190 }
191 else
192 {
193 progress = ::invalid_progress;
194 }
195
196 set_progress(m_widget.write_progress, progress);
197
198 m_current_state = new_state;
199 if (old_state != new_state)
200 {
201 emit imageProviderStateChanged(old_state, new_state);
202 }
203}
204
205void
207{
208 switch (viewMode)
209 {
210 case ViewMode::Full:
211 m_widget.line->show();
212 m_widget.channel_configs->show();
213 m_widget.buttons->show();
214 m_widget.label_name->show();
215 m_widget.ice_proxy_finder->show();
216 break;
218 m_widget.line->hide();
219 m_widget.channel_configs->hide();
220 m_widget.buttons->hide();
221 m_widget.label_name->hide();
222 m_widget.ice_proxy_finder->hide();
223 break;
224 }
225}
226
227void
228visionx::ImageProviderConfigWidget::build_ui_from_configs(
229 const std::vector<imrec::ChannelConfig>& configs,
230 const std::vector<imrec::ChannelPreferences>& prefs_list)
231{
232 ARMARX_CHECK(configs.size() == prefs_list.size());
233
234 for (ChannelConfigWidget* config_widget : m_channel_config_widgets)
235 {
236 m_widget.channel_configs->layout()->removeWidget(config_widget);
237 config_widget->deleteLater();
238 }
239
240 for (unsigned int i = 0; i < configs.size(); ++i)
241 {
242 add_channel_conf_widget(configs.at(i), prefs_list.at(i));
243 }
244}
245
246void
247visionx::ImageProviderConfigWidget::add_channel_conf_widget(
248 const imrec::ChannelConfig& channel_config,
249 const imrec::ChannelPreferences& channel_prefs)
250{
251 // Assert that there's no channel config with the same name in the list.
252 ARMARX_CHECK(is_channel_name_unique(channel_config.name));
253
255 new ChannelConfigWidget{m_widget.channel_configs, channel_config, channel_prefs};
256
257 m_channel_config_widgets.push_back(ccw);
258 m_widget.channel_configs->layout()->addWidget(ccw);
259
260 connect(ccw,
262 this,
263 &ImageProviderConfigWidget::channel_renamed);
264}
265
266void
267visionx::ImageProviderConfigWidget::update_channel_list()
268{
269 std::vector<imrec::ChannelPreferences> prefs_list = get_channel_prefs();
270
271 if (prefs_list.empty())
272 {
273 return;
274 }
275
276 const bool image_provider_changed = m_channel_config_widgets.size() != prefs_list.size();
277 if (image_provider_changed)
278 {
279 // Delete all widgets and instantiate new ones.
280 for (ChannelConfigWidget* ccw : m_channel_config_widgets)
281 {
282 m_widget.channel_configs->layout()->removeWidget(ccw);
283 ccw->deleteLater();
284 }
285 m_channel_config_widgets.clear();
286
287 // Build new UI.
288 std::vector<imrec::ChannelConfig> ccs;
289 for (const imrec::ChannelPreferences& prefs : prefs_list)
290 {
291 imrec::ChannelConfig cc;
292 cc.disabled = false;
293 cc.name = prefs.name;
295 ccs.push_back(cc);
296 }
297 build_ui_from_configs(ccs, prefs_list);
298 }
299}
300
301std::vector<visionx::imrec::ChannelPreferences>
302visionx::ImageProviderConfigWidget::get_channel_prefs()
303{
304 try
305 {
306 return m_iceman->getProxy<RecordingImageProviderInterfacePrx>(m_image_provider_name, "")
307 ->getImageRecordingChannelPreferences();
308 }
309 catch (...)
310 {
311 return {};
312 }
313}
314
315bool
316visionx::ImageProviderConfigWidget::is_channel_name_unique(const std::string& name)
317{
318 return std::find_if(m_channel_config_widgets.begin(),
319 m_channel_config_widgets.end(),
320 [&](const auto& e)
321 { return e->getChannelName() == name; }) == m_channel_config_widgets.end();
322}
323
324void
325visionx::ImageProviderConfigWidget::state_changed(std::optional<imrec::State>,
326 std::optional<imrec::State> new_state)
327{
328 if (new_state.has_value() and
329 (new_state.value() == imrec::State::running or new_state.value() == imrec::State::writing))
330 {
331 if (new_state.value() == imrec::State::running)
332 {
333 m_current_icon_name = "imrec_running";
334 }
335 else
336 {
337 m_current_icon_name = "imrec_write";
338 }
339 m_blink_timer->start();
340 }
341 else
342 {
343 m_blink_timer->stop();
344 }
345
346 QString icon_name;
347
348 if (new_state.has_value())
349 {
350 switch (new_state.value())
351 {
352 case imrec::State::ready:
353 m_widget.status->setText("ready");
354 icon_name = ":/icons/imrec_ready.ico";
355 break;
356 case imrec::State::scheduled:
357 m_widget.status->setText("scheduled");
358 icon_name = ":/icons/imrec_scheduled.ico";
359 break;
360 case imrec::State::running:
361 m_widget.status->setText("recording");
362 icon_name = ":/icons/imrec_running.ico";
363 break;
364 case imrec::State::stopping:
365 m_widget.status->setText("stopping");
366 icon_name = ":/icons/imrec_stopping.ico";
367 break;
368 case imrec::State::writing:
369 m_widget.status->setText("writing");
370 icon_name = ":/icons/imrec_write.ico";
371 break;
372 case imrec::State::offline:
373 m_widget.status->setText("offline");
374 icon_name = ":/icons/imrec_offline.ico";
375 break;
376 }
377 }
378 else
379 {
380 m_widget.status->setText("not configured");
381 icon_name = ":/icons/imrec_not_configured.ico";
382 }
383
384 QIcon icon;
385 icon.addFile(icon_name, QSize(), QIcon::Normal, QIcon::On);
386 m_widget.icon_placeholder->setPixmap(icon.pixmap(20, 20));
387}
388
389void
390visionx::ImageProviderConfigWidget::blink()
391{
392 QString icon_name;
393 if (m_icon_blink)
394 {
395 icon_name = QString::fromStdString(":/icons/" + m_current_icon_name + ".ico");
396 }
397 else
398 {
399 icon_name = QString::fromStdString(":/icons/" + m_current_icon_name + "_dark.ico");
400 }
401 m_icon_blink = not m_icon_blink;
402
403 QIcon icon;
404 icon.addFile(icon_name, QSize(), QIcon::Normal, QIcon::On);
405 m_widget.icon_placeholder->setPixmap(icon.pixmap(20, 20));
406}
407
408void
409visionx::ImageProviderConfigWidget::channel_renamed(const std::string& old_name,
410 const std::string& new_name)
411{
412 auto it = std::find_if(m_channel_config_widgets.begin(),
413 m_channel_config_widgets.end(),
414 [&](const auto& c) { return c->getChannelName() == old_name; });
415 if (it == m_channel_config_widgets.end())
416 {
417 ARMARX_ERROR << "Internal error, a channel was renamed which is not known to parent "
418 << "widget. Old name: '" << old_name << "'. New name: '" << new_name << "'.";
419 return;
420 }
421 ChannelConfigWidget* ccw = *it;
422 is_channel_name_unique(new_name) ? ccw->confirmChannelName(new_name)
423 : ccw->rejectChannelName(new_name);
424}
425
426void
427visionx::ImageProviderConfigWidget::image_provider_renamed(const QString& q_new_name)
428{
429 const std::string new_name = simox::alg::trim_copy(q_new_name.toStdString());
430 const std::string old_name = m_image_provider_name;
431
432 if (not q_new_name.isEmpty())
433 {
434 if (new_name != old_name)
435 {
436 emit imageProviderRenamed(old_name, new_name);
437 }
438 }
439 else
440 {
441 m_ice_proxy_finder->setDefaultSelectedProxy(QString::fromStdString(old_name));
442 }
443}
444
445void
446visionx::ImageProviderConfigWidget::image_provider_removed()
447{
448 emit imageProviderRemoved(m_image_provider_name);
449}
constexpr T c
Widget to conveniently retrieve a proxy instance name of a specific interface type (the template para...
void channelRenamed(const std::string &old_name, const std::string &new_name)
void confirmChannelName(const std::string &new_name)
void rejectImageProviderName(const std::string &new_name)
void confirmImageProviderName(const std::string &new_name)
void setImageProviderStatus(std::optional< visionx::imrec::Status > status)
void imageProviderStateChanged(std::optional< imrec::State > old_state, std::optional< imrec::State > new_state)
std::vector< visionx::imrec::ChannelConfig > toChannelConfigs() const
ImageProviderConfigWidget(QWidget *parent, armarx::IceManagerPtr iceman, const std::string &image_provider_name, const visionx::imrec::ChannelConfigs &channel_configs)
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
IceUtil::Handle< IceManager > IceManagerPtr
IceManager smart pointer.
Definition ArmarXFwd.h:39
const std::string & format2str(const Format format)