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 
42 namespace
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,
65  armarx::IceManagerPtr iceman,
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 
128 {
129 }
130 
131 void
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 
140 void
142 {
143  // TODO: Display fancy graphics.
144  ARMARX_WARNING << "Invalid name '" << new_name << "' for image provider (already taken).";
145 }
146 
147 std::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 
159 void
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 
205 void
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 
227 void
228 visionx::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 
246 void
247 visionx::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 
254  ChannelConfigWidget* ccw =
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 
266 void
267 visionx::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 
301 std::vector<visionx::imrec::ChannelPreferences>
302 visionx::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 
315 bool
316 visionx::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 
324 void
325 visionx::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;
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 
389 void
390 visionx::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 
408 void
409 visionx::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 
426 void
427 visionx::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 
445 void
446 visionx::ImageProviderConfigWidget::image_provider_removed()
447 {
448  emit imageProviderRemoved(m_image_provider_name);
449 }
visionx::ImageProviderConfigWidget::imageProviderStateChanged
void imageProviderStateChanged(std::optional< imrec::State > old_state, std::optional< imrec::State > new_state)
visionx::imrec::Format::bmp_img_seq
@ bmp_img_seq
visionx::ImageProviderConfigWidget::toChannelConfigs
std::vector< visionx::imrec::ChannelConfig > toChannelConfigs() const
Definition: ImageProviderConfigWidget.cpp:148
visionx::ImageProviderConfigWidget::rejectImageProviderName
void rejectImageProviderName(const std::string &new_name)
Definition: ImageProviderConfigWidget.cpp:141
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
visionx::ChannelConfigWidget
Definition: ChannelConfigWidget.h:40
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
visionx::ImageProviderConfigWidget::setViewMode
void setViewMode(ViewMode viewMode)
Definition: ImageProviderConfigWidget.cpp:206
visionx::ImageProviderConfigWidget::setImageProviderStatus
void setImageProviderStatus(std::optional< visionx::imrec::Status > status)
Definition: ImageProviderConfigWidget.cpp:160
visionx::imrec::format2str
const std::string & format2str(const Format format)
Definition: public_api.cpp:109
armarx::status
status
Definition: FiniteStateMachine.h:244
ChannelConfigWidget.h
visionx::ViewMode::StatusOnly
@ StatusOnly
GfxTL::On
OnOff< true > On
Definition: OnOff.h:12
max
T max(T t1, T t2)
Definition: gdiam.h:51
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
visionx::ViewMode::Full
@ Full
armarx::transform
auto transform(const Container< InputT, Alloc > &in, OutputT(*func)(InputT const &)) -> Container< OutputT, typename std::allocator_traits< Alloc >::template rebind_alloc< OutputT >>
Convenience function (with less typing) to transform a container of type InputT into the same contain...
Definition: algorithm.h:351
IceUtil::Handle< IceManager >
visionx::imrecman::offline
@ offline
Definition: ImageRecordingManagerInterface.ice:48
visionx::ImageProviderConfigWidget::confirmImageProviderName
void confirmImageProviderName(const std::string &new_name)
Definition: ImageProviderConfigWidget.cpp:132
visionx::ChannelConfigWidget::channelRenamed
void channelRenamed(const std::string &old_name, const std::string &new_name)
armarx::IceProxyFinder
Definition: StatechartViewerController.h:49
ImageRecorderWidgetController.h
ImageProviderConfigWidget.h
Logging.h
min
T min(T t1, T t2)
Definition: gdiam.h:44
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
visionx::ImageProviderConfigWidget::ImageProviderConfigWidget
ImageProviderConfigWidget(QWidget *parent, armarx::IceManagerPtr iceman, const std::string &image_provider_name, const visionx::imrec::ChannelConfigs &channel_configs)
Definition: ImageProviderConfigWidget.cpp:63
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
visionx::ImageProviderConfigWidget::~ImageProviderConfigWidget
virtual ~ImageProviderConfigWidget()
Definition: ImageProviderConfigWidget.cpp:127
visionx::ViewMode
ViewMode
Definition: ImageProviderConfigWidget.h:53