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
40 
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 set_progress(QProgressBar* progress_bar, const Progress& progress)
55  {
56  progress_bar->setMinimum(progress.min);
57  progress_bar->setMaximum(progress.max);
58  progress_bar->setValue(progress.val);
59  }
60 }
61 
62 
63 visionx::ImageProviderConfigWidget::ImageProviderConfigWidget(QWidget* parent, armarx::IceManagerPtr iceman, const std::string& image_provider_name, const visionx::imrec::ChannelConfigs& channel_configs)
64  : QWidget(parent),
65  m_iceman{iceman},
66  m_image_provider_name{image_provider_name}
67 {
68  m_widget.setupUi(this);
69  connect(this, &ImageProviderConfigWidget::imageProviderStateChanged, this, &ImageProviderConfigWidget::state_changed);
70  connect(m_widget.remove_image_provider, &QPushButton::clicked, this, &ImageProviderConfigWidget::image_provider_removed);
71 
72  const QString q_image_provider_name = QString::fromStdString(m_image_provider_name);
73  m_widget.configs->setTitle(QString{"Image provider: "} + q_image_provider_name);
74 
75  // Replace or remove dummy values from the UI designer.
76  set_progress(m_widget.write_progress, ::invalid_progress);
77  m_widget.ice_proxy_finder_placeholder->deleteLater(); // Remove placeholder.
78 
79  // Timer for blink animation while recording/writing.
80  m_blink_timer = new QTimer(this);
81  m_blink_timer->setSingleShot(false);
82  m_blink_timer->setInterval(750);
83  connect(m_blink_timer, &QTimer::timeout, this, &ImageProviderConfigWidget::blink);
84 
85  // Ice proxy finder to select a recording image provider.
87  m_widget.ice_proxy_finder->layout()->addWidget(m_ice_proxy_finder);
88  m_ice_proxy_finder->setIceManager(iceman);
89  m_ice_proxy_finder->setDefaultSelectedProxyAsItem(q_image_provider_name);
90  m_ice_proxy_finder->setSearchMask("*");
91  connect(m_ice_proxy_finder->getProxyNameComboBox(), SIGNAL(editTextChanged(QString)), this, SLOT(image_provider_renamed(QString)));
92 
93  // Initialise UI according to channel settings and channel preferences.
94  std::vector<imrec::ChannelPreferences> channel_prefs_list;
95  std::vector<imrec::ChannelPreferences> reported_channel_prefs_list = get_channel_prefs();
96  const bool use_default_channel_prefs = reported_channel_prefs_list.size() != channel_configs.size();
97  for (unsigned int i = 0; i < channel_configs.size(); ++i)
98  {
99  imrec::ChannelPreferences channel_prefs;
100  if (use_default_channel_prefs)
101  {
102  channel_prefs.name = "c" + std::to_string(i);
103  channel_prefs.requiresLossless = false;
104  }
105  else
106  {
107  channel_prefs = reported_channel_prefs_list.at(i);
108  }
109  channel_prefs_list.push_back(channel_prefs);
110  }
111 
112  build_ui_from_configs(channel_configs, channel_prefs_list);
113 }
114 
115 
117 {
118 
119 }
120 
121 
122 void
124 {
125  m_widget.configs->setTitle(QString::fromStdString("Image provider: " + new_name));
126  m_ice_proxy_finder->setDefaultSelectedProxyAsItem(QString::fromStdString(new_name));
127  m_image_provider_name = new_name;
128  update_channel_list();
129 }
130 
131 
132 void
134 {
135  // TODO: Display fancy graphics.
136  ARMARX_WARNING << "Invalid name '" << new_name << "' for image provider (already taken).";
137 }
138 
139 
140 std::vector<visionx::imrec::ChannelConfig>
142 {
143  const bool disabled = false /*not m_widget.configs->isChecked()*/ ;
144  std::vector<visionx::imrec::ChannelConfig> ccs;
145  std::transform(m_channel_config_widgets.begin(), m_channel_config_widgets.end(),
146  std::back_inserter(ccs), [&](const auto * ccw)
147  {
148  return ccw->toChannelConfig(disabled);
149  });
150  return ccs;
151 }
152 
153 
154 void
156 {
157  const std::optional<imrec::State> old_state = m_current_state;
158  std::optional<imrec::State> new_state;
159  if (status.has_value())
160  {
161  new_state = status.value().type;
162  }
163 
164  Progress progress;
165 
166  if (status.has_value() and status.value().type != imrec::State::offline)
167  {
168  const imrec::Status s = status.value();
169 
170  if (s.type == imrec::State::ready and s.framesWritten == 0 and s.framesBuffered == 0)
171  {
172  progress = ::invalid_progress;
173  }
174  else if (s.type == imrec::State::scheduled)
175  {
176  progress = ::indefinite_progress;
177  }
178  else
179  {
180  progress.min = 0;
181  progress.max = s.framesWritten + s.framesBuffered;
182  progress.val = s.framesWritten;
183  }
184  }
185  else
186  {
187  progress = ::invalid_progress;
188  }
189 
190  set_progress(m_widget.write_progress, progress);
191 
192  m_current_state = new_state;
193  if (old_state != new_state)
194  {
195  emit imageProviderStateChanged(old_state, new_state);
196  }
197 }
198 
199 
200 void
202 {
203  switch (viewMode)
204  {
205  case ViewMode::Full:
206  m_widget.line->show();
207  m_widget.channel_configs->show();
208  m_widget.buttons->show();
209  m_widget.label_name->show();
210  m_widget.ice_proxy_finder->show();
211  break;
213  m_widget.line->hide();
214  m_widget.channel_configs->hide();
215  m_widget.buttons->hide();
216  m_widget.label_name->hide();
217  m_widget.ice_proxy_finder->hide();
218  break;
219  }
220 }
221 
222 
223 void
224 visionx::ImageProviderConfigWidget::build_ui_from_configs(const std::vector<imrec::ChannelConfig>& configs, const std::vector<imrec::ChannelPreferences>& prefs_list)
225 {
226  ARMARX_CHECK(configs.size() == prefs_list.size());
227 
228  for (ChannelConfigWidget* config_widget : m_channel_config_widgets)
229  {
230  m_widget.channel_configs->layout()->removeWidget(config_widget);
231  config_widget->deleteLater();
232  }
233 
234  for (unsigned int i = 0; i < configs.size(); ++i)
235  {
236  add_channel_conf_widget(configs.at(i), prefs_list.at(i));
237  }
238 }
239 
240 
241 void
242 visionx::ImageProviderConfigWidget::add_channel_conf_widget(const imrec::ChannelConfig& channel_config, const imrec::ChannelPreferences& channel_prefs)
243 {
244  // Assert that there's no channel config with the same name in the list.
245  ARMARX_CHECK(is_channel_name_unique(channel_config.name));
246 
247  ChannelConfigWidget* ccw = new ChannelConfigWidget{m_widget.channel_configs, channel_config, channel_prefs};
248 
249  m_channel_config_widgets.push_back(ccw);
250  m_widget.channel_configs->layout()->addWidget(ccw);
251 
252  connect(ccw, &ChannelConfigWidget::channelRenamed, this, &ImageProviderConfigWidget::channel_renamed);
253 }
254 
255 
256 void
257 visionx::ImageProviderConfigWidget::update_channel_list()
258 {
259  std::vector<imrec::ChannelPreferences> prefs_list = get_channel_prefs();
260 
261  if (prefs_list.empty())
262  {
263  return;
264  }
265 
266  const bool image_provider_changed = m_channel_config_widgets.size() != prefs_list.size();
267  if (image_provider_changed)
268  {
269  // Delete all widgets and instantiate new ones.
270  for (ChannelConfigWidget* ccw : m_channel_config_widgets)
271  {
272  m_widget.channel_configs->layout()->removeWidget(ccw);
273  ccw->deleteLater();
274  }
275  m_channel_config_widgets.clear();
276 
277  // Build new UI.
278  std::vector<imrec::ChannelConfig> ccs;
279  for (const imrec::ChannelPreferences& prefs : prefs_list)
280  {
281  imrec::ChannelConfig cc;
282  cc.disabled = false;
283  cc.name = prefs.name;
285  ccs.push_back(cc);
286  }
287  build_ui_from_configs(ccs, prefs_list);
288  }
289 }
290 
291 
292 std::vector<visionx::imrec::ChannelPreferences>
293 visionx::ImageProviderConfigWidget::get_channel_prefs()
294 {
295  try
296  {
297  return m_iceman->getProxy<RecordingImageProviderInterfacePrx>(m_image_provider_name, "")->getImageRecordingChannelPreferences();
298  }
299  catch (...)
300  {
301  return {};
302  }
303 }
304 
305 
306 bool
307 visionx::ImageProviderConfigWidget::is_channel_name_unique(const std::string& name)
308 {
309  return std::find_if(m_channel_config_widgets.begin(), m_channel_config_widgets.end(), [&](const auto & e)
310  {
311  return e->getChannelName() == name;
312  }) == m_channel_config_widgets.end();
313 }
314 
315 
316 void
317 visionx::ImageProviderConfigWidget::state_changed(std::optional<imrec::State>, std::optional<imrec::State> new_state)
318 {
319  if (new_state.has_value() and (new_state.value() == imrec::State::running or new_state.value() == imrec::State::writing))
320  {
321  if (new_state.value() == imrec::State::running)
322  {
323  m_current_icon_name = "imrec_running";
324  }
325  else
326  {
327  m_current_icon_name = "imrec_write";
328  }
329  m_blink_timer->start();
330  }
331  else
332  {
333  m_blink_timer->stop();
334  }
335 
336  QString icon_name;
337 
338  if (new_state.has_value())
339  {
340  switch (new_state.value())
341  {
342  case imrec::State::ready:
343  m_widget.status->setText("ready");
344  icon_name = ":/icons/imrec_ready.ico";
345  break;
346  case imrec::State::scheduled:
347  m_widget.status->setText("scheduled");
348  icon_name = ":/icons/imrec_scheduled.ico";
349  break;
350  case imrec::State::running:
351  m_widget.status->setText("recording");
352  icon_name = ":/icons/imrec_running.ico";
353  break;
354  case imrec::State::stopping:
355  m_widget.status->setText("stopping");
356  icon_name = ":/icons/imrec_stopping.ico";
357  break;
358  case imrec::State::writing:
359  m_widget.status->setText("writing");
360  icon_name = ":/icons/imrec_write.ico";
361  break;
363  m_widget.status->setText("offline");
364  icon_name = ":/icons/imrec_offline.ico";
365  break;
366  }
367  }
368  else
369  {
370  m_widget.status->setText("not configured");
371  icon_name = ":/icons/imrec_not_configured.ico";
372  }
373 
374  QIcon icon;
375  icon.addFile(icon_name, QSize(), QIcon::Normal, QIcon::On);
376  m_widget.icon_placeholder->setPixmap(icon.pixmap(20, 20));
377 }
378 
379 
380 void
381 visionx::ImageProviderConfigWidget::blink()
382 {
383  QString icon_name;
384  if (m_icon_blink)
385  {
386  icon_name = QString::fromStdString(":/icons/" + m_current_icon_name + ".ico");
387  }
388  else
389  {
390  icon_name = QString::fromStdString(":/icons/" + m_current_icon_name + "_dark.ico");
391  }
392  m_icon_blink = not m_icon_blink;
393 
394  QIcon icon;
395  icon.addFile(icon_name, QSize(), QIcon::Normal, QIcon::On);
396  m_widget.icon_placeholder->setPixmap(icon.pixmap(20, 20));
397 }
398 
399 
400 void
401 visionx::ImageProviderConfigWidget::channel_renamed(const std::string& old_name, const std::string& new_name)
402 {
403  auto it = std::find_if(m_channel_config_widgets.begin(), m_channel_config_widgets.end(), [&](const auto & c)
404  {
405  return c->getChannelName() == old_name;
406  });
407  if (it == m_channel_config_widgets.end())
408  {
409  ARMARX_ERROR << "Internal error, a channel was renamed which is not known to parent "
410  << "widget. Old name: '" << old_name << "'. New name: '" << new_name << "'.";
411  return;
412  }
413  ChannelConfigWidget* ccw = *it;
414  is_channel_name_unique(new_name) ? ccw->confirmChannelName(new_name) : ccw->rejectChannelName(new_name);
415 }
416 
417 
418 void
419 visionx::ImageProviderConfigWidget::image_provider_renamed(const QString& q_new_name)
420 {
421  const std::string new_name = simox::alg::trim_copy(q_new_name.toStdString());
422  const std::string old_name = m_image_provider_name;
423 
424  if (not q_new_name.isEmpty())
425  {
426  if (new_name != old_name)
427  {
428  emit imageProviderRenamed(old_name, new_name);
429  }
430  }
431  else
432  {
433  m_ice_proxy_finder->setDefaultSelectedProxy(QString::fromStdString(old_name));
434  }
435 }
436 
437 
438 void
439 visionx::ImageProviderConfigWidget::image_provider_removed()
440 {
441  emit imageProviderRemoved(m_image_provider_name);
442 }
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:141
visionx::ImageProviderConfigWidget::rejectImageProviderName
void rejectImageProviderName(const std::string &new_name)
Definition: ImageProviderConfigWidget.cpp:133
GfxTL::On
OnOff< true > On
Definition: OnOff.h:10
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
visionx::ChannelConfigWidget
Definition: ChannelConfigWidget.h:41
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:201
visionx::ImageProviderConfigWidget::setImageProviderStatus
void setImageProviderStatus(std::optional< visionx::imrec::Status > status)
Definition: ImageProviderConfigWidget.cpp:155
visionx::imrec::format2str
const std::string & format2str(const Format format)
Definition: public_api.cpp:145
armarx::status
status
Definition: FiniteStateMachine.h:259
ChannelConfigWidget.h
visionx::ViewMode::StatusOnly
@ StatusOnly
max
T max(T t1, T t2)
Definition: gdiam.h:48
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:189
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:40
visionx::ViewMode::Full
@ Full
IceUtil::Handle< IceManager >
visionx::imrecman::offline
@ offline
Definition: ImageRecordingManagerInterface.ice:49
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:315
visionx::ImageProviderConfigWidget::confirmImageProviderName
void confirmImageProviderName(const std::string &new_name)
Definition: ImageProviderConfigWidget.cpp:123
visionx::ChannelConfigWidget::channelRenamed
void channelRenamed(const std::string &old_name, const std::string &new_name)
armarx::IceProxyFinder
Definition: StatechartViewerController.h:51
ImageRecorderWidgetController.h
ImageProviderConfigWidget.h
Logging.h
min
T min(T t1, T t2)
Definition: gdiam.h:42
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
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:116
visionx::ViewMode
ViewMode
Definition: ImageProviderConfigWidget.h:52