SkillDetailsTreeWidget.cpp
Go to the documentation of this file.
2 
3 #include <optional>
4 
5 #include <QApplication>
6 #include <QClipboard>
7 #include <QHeaderView>
8 #include <QResizeEvent>
9 #include <QVBoxLayout>
10 #include <qchar.h>
11 #include <qcheckbox.h>
12 #include <qmessagebox.h>
13 #include <qpushbutton.h>
14 #include <qtreewidget.h>
15 
17 
22 
23 namespace armarx::skills::gui
24 {
25  SkillDetailsTreeWidget::SkillDetailsTreeWidget(std::shared_ptr<SkillManagerWrapper> _memory,
26  QWidget* parent) :
27  QTreeWidget(parent), MemoryCommunicatorBase(_memory)
28  {
29  setupUi();
30  }
31 
32  std::optional<SkillID>
34  {
35  if (shownSkill.has_value())
36  {
37  return shownSkill.value().skillId;
38  }
39  else
40  {
41  return std::nullopt;
42  }
43  }
44 
45  void
47  {
48  // dont touch the widget if the skill id didn't change
49  // note: this is only relevant when periodic updates are enabled
50  /*
51  if (shownSkill.has_value() && skillId == shownSkill.value().skillId)
52  return;
53  */
54 
55  // check the parameters: did they change?
56  if (shownSkill.has_value())
57  {
58  auto remDesc = shownSkill.value().descr;
59  if (descr.rootProfileDefaults != remDesc.rootProfileDefaults)
60  {
61  // TODO: ask the user if they want to reset to defaults
62  // for now, we just overwrite without asking... (and do nothing)
63  }
64  // other cases: if the parameter types change, we *have* to reset; else the skill
65  // cannot be started with the parameters.
66  // same goes for the result type.
67  }
68 
69  this->resetWidget();
70 
71  auto aron_args = descr.parametersType;
72  auto default_args_of_profile = descr.rootProfileDefaults;
73  // ideally we want to use the invisible root item, but aron expects a parent...
74  QTreeWidgetItem* aronTreeWidgetItem = new QTreeWidgetItem(this);
75  aronTreeWidgetItem->setText(0, QString::fromStdString("Parameters"));
76 
77  aronTreeWidgetController = std::make_shared<AronTreeWidgetController>(
78  this, aronTreeWidgetItem, aron_args, default_args_of_profile);
79 
80 
81  this->expandAll();
83 
84  emit updated(skillId);
85 
86  // update the ShownSkill
87  shownSkill = {skillId, descr, aronTreeWidgetController->convertToAron()};
88  }
89 
90  void
92  {
93  this->aronTreeWidgetController = nullptr;
94  }
95 
96  void
98  {
99  if (not shownSkill.has_value())
100  {
101  return;
102  }
103  skills::SkillID sid = shownSkill.value().skillId;
104 
105  // we assume the id to be fully specified, as it is checked while constructing
106  // sanity check
108 
109  // maybe the search is empty?
110  auto skillsMap = update.skills;
111  if (skillsMap.count(sid.providerId.value()) == 0 ||
112  skillsMap.at(sid.providerId.value()).count(sid) == 0)
113  {
114  this->resetWidget();
115  return;
116  }
117 
118  auto descr = update.skills.at(sid.providerId.value()).at(sid);
119 
120  // only triggers if the description does not match
121  // TODO: for some reason the == operator does not work for the aron ObjectPtrs (data and type) in the description.
122  // We exclude them here, but it should be adressed elsewhere...
123  if (descr.skillId != shownSkill->descr.skillId || descr.timeout != shownSkill->descr.timeout || descr.description != shownSkill->descr.description)
124  {
125  ARMARX_WARNING << "The skill description of the currently shown skill has changed. Resetting the widget...";
126  this->updateContents(sid, descr);
127  }
128  }
129 
130  void
131  SkillDetailsTreeWidget::setupUi()
132  {
133  this->setColumnCount(3);
134 
135  this->setContextMenuPolicy(Qt::CustomContextMenu);
136  this->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
137 
138  QTreeWidgetItem* qtreewidgetitem2 = this->headerItem();
139  qtreewidgetitem2->setText(3, "defaultValue (hidden in GUI)");
140  qtreewidgetitem2->setText(2, "Type");
141  qtreewidgetitem2->setText(1, "Value");
142  qtreewidgetitem2->setText(0, "Key");
143 
144  setColumnHidden(3, true);
145  }
146 
147  bool
148  SkillDetailsTreeWidget::askUserToConfirmWidgetReset()
149  {
150  std::string msg = "The skill details widget will be reset. All changes will be lost, unless saved.";
151  QMessageBox msgBox;
152  msgBox.setText(QString::fromStdString(msg));
153  QCheckBox* ignoreCheckbox = new QCheckBox("Do not ask again in this session.");
154  msgBox.setCheckBox(ignoreCheckbox);
155  QPushButton* copyParamsButton = msgBox.addButton(tr("Copy Parameters && Close"), QMessageBox::ActionRole);
156  QPushButton* copySkillIdButton = msgBox.addButton(tr("Copy SkillID && Close"), QMessageBox::ActionRole);
157  QPushButton* closeWithoutSavingButton = msgBox.addButton(tr("Close"), QMessageBox::ActionRole);
158 
159  msgBox.setDefaultButton(closeWithoutSavingButton);
160  QObject::connect(ignoreCheckbox, &QCheckBox::stateChanged, [this](int state){
161  if (static_cast<Qt::CheckState>(state) == Qt::CheckState::Checked) {
162  this->showWidgetResetConfirmation_ = false;
163  }
164  });
165 
166  connect(copyParamsButton, &QPushButton::pressed, this, &SkillDetailsTreeWidget::copyCurrentConfig);
167  msgBox.exec();
168 
169  return true;
170  }
171 
172  bool
173  SkillDetailsTreeWidget::checkIfParametersAreModified()
174  {
175  if (not shownSkill.has_value())
176  {
177  return false;
178  }
179 
180  auto defaults = shownSkill->originalParameters;
181 
182  if (this->aronTreeWidgetController.get() == nullptr)
183  {
184  return false;
185  }
186 
187  auto params = this->aronTreeWidgetController->convertToAron();
188 
189  if (defaults.get() == nullptr and params.get() == nullptr)
190  {
191  return false;
192  }
193 
194  bool modified = not(*defaults == *params);
195  if (modified)
196  {
197  ARMARX_DEBUG << "The parameters have been modified.";
198  }
199  return modified;
200  }
201 
202  /**
203  * Problem: columns 0 and 1 have arbitrary size; so we want to limit their size, to make sure
204  * everything is visible without scrolling. Column 2 is limited by design, as it only contains
205  * type information.
206  */
207  void
209  {
210  // take remainder of width (which we want to assign to dynamic columns)
211  const int widthRemainder = this->width() - typeWidth;
212 
213  // we want to assign half of it to each dynamic column
214  const int dynamicColumnSize = widthRemainder / 2;
215 
216  // set width...
217 
218  this->setColumnWidth(0, dynamicColumnSize);
219 
220  this->setColumnWidth(1, dynamicColumnSize);
221  }
222 
224  {
225  if (not shownSkill.has_value())
226  {
227  return;
228  }
229 
230  auto params = memory->getLatestParametersForSkill(shownSkill->skillId);
231 
232  if (not params.has_value())
233  {
234  return;
235  }
236 
237  ARMARX_INFO << "Reloaded parameters from the last execution";
238  aronTreeWidgetController->setFromAron(params.value());
239  }
240 
242  {
243  auto executions = memory->getExecutions();
244  if (executions.empty() || not shownSkill.has_value())
245  {
246  return;
247  }
248 
249 
250  // find the most recent execution with a matching skill id
251 
252  std::optional<armarx::skills::SkillStatusUpdate> found = std::nullopt;
253  for (auto& execution : executions)
254  {
255  if (execution.first.skillId == shownSkill->skillId)
256  {
257  if (not found.has_value())
258  {
259  found = execution.second;
260  }
261  else
262  {
263  if (found->executionId.executionStartedTime < execution.first.executionStartedTime)
264  {
265  // in this case, we found a more recent execution.
266  found = execution.second;
267  }
268  }
269  }
270  }
271 
272  if (not found.has_value())
273  {
274  // we didn't find an entry for the execution id
275  ARMARX_INFO<< "No execution for the skill " << shownSkill->skillId.toString() << " has been found in the memory. The parametrization cannot be reloaded.";
276  return;
277  }
278  auto params = found->parameters;
279 
280  ARMARX_INFO << "Reloading parameters of skill " << found->executionId.skillId;
281  this->aronTreeWidgetController->setFromAron(params);
282  }
283 
286  {
287  // create argument aron (if there is an accepted type set)
288  if (aronTreeWidgetController)
289  {
290  return aronTreeWidgetController->convertToAron();
291  }
292  return nullptr;
293  }
294 
295  void
297  {
298  auto data = getConfigAsAron();
299  if (!data)
300  {
301  return;
302  }
303 
305  QClipboard* clipboard = QApplication::clipboard();
306  clipboard->setText(QString::fromStdString(json.dump(2)));
307  }
308 
310  {
311  if (not shownSkill.has_value())
312  {
313  return;
314  }
315 
316  QClipboard* clipboard = QApplication::clipboard();
317  clipboard->setText(QString::fromStdString(shownSkill->skillId.toString()));
318  }
319 
320  void
322  {
323  QClipboard* clipboard = QApplication::clipboard();
324  std::string s = clipboard->text().toStdString();
325  nlohmann::json json = nlohmann::json::parse(s);
326  auto data =
328 
329  if (!aronTreeWidgetController)
330  {
331  return;
332  }
333 
334  aronTreeWidgetController->setFromAron(data);
335  }
336 
337  void
339  {
340  // this will always reset the args to the root profile
341  // good while there is only the root, not good when profiles are properly implemented
342 
343 
344  if (!shownSkill.has_value())
345  {
346  return;
347  }
348  skills::SkillID& skillId = shownSkill.value().skillId;
349  const auto skills = memory->getSkills();
351 
352  // find description
353  // did the provider die?
354  if (skills.count(skillId.providerId.value()) == 0 ||
355  skills.at(skillId.providerId.value()).count(skillId) == 0)
356  return;
357  skills::SkillDescription descr = skills.at(skillId.providerId.value()).at(skillId);
358  this->updateContents(skillId, descr);
359  }
360 
361  void
363  {
364  if (checkIfParametersAreModified())
365  {
366  if (shownSkill.has_value())
367  {
368  ARMARX_IMPORTANT << "A skill parametrization has been lost in the GUI. It can now be reloaded.";
369  memory->addParametersToHistory(shownSkill->skillId, aronTreeWidgetController->convertToAron());
370  emit updated(shownSkill->skillId);
371  }
372  }
373  this->clear();
374  this->shownSkill = std::nullopt;
375  aronTreeWidgetController = nullptr;
376  }
377 
378 
379 } // namespace armarx::skills::gui
SkillDetailsTreeWidget.h
skills
This file is part of ArmarX.
armarx::skills::gui::SkillDetailsTreeWidget::resetCurrentConfig
void resetCurrentConfig()
Definition: SkillDetailsTreeWidget.cpp:338
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:190
SkillID.h
armarx::skills::gui::SkillDetailsTreeWidget::updateGui
void updateGui(SkillManagerWrapper::Snapshot update)
Definition: SkillDetailsTreeWidget.cpp:97
armarx::skills::gui::SkillDetailsTreeWidget::reloadLastParameters
void reloadLastParameters()
Definition: SkillDetailsTreeWidget.cpp:223
armarx::skills::SkillDescription
Definition: SkillDescription.h:17
armarx::aron::data::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON
static nlohmann::json ConvertToNlohmannJSON(const data::VariantPtr &)
Definition: NLohmannJSONConverter.cpp:10
armarx::skills::gui::SkillDetailsTreeWidget::SkillDetailsTreeWidget
SkillDetailsTreeWidget(std::shared_ptr< SkillManagerWrapper > _memory, QWidget *parent=nullptr)
Definition: SkillDetailsTreeWidget.cpp:25
armarx::aron::data::converter::AronNlohmannJSONConverter::ConvertFromNlohmannJSONObject
static data::DictPtr ConvertFromNlohmannJSONObject(const nlohmann::json &, const armarx::aron::Path &p={})
Definition: NLohmannJSONConverter.cpp:25
armarx::skills::SkillID::providerId
std::optional< ProviderID > providerId
Definition: SkillID.h:40
armarx::skills::gui::SkillDetailsTreeWidget::resizeContents
void resizeContents()
Problem: columns 0 and 1 have arbitrary size; so we want to limit their size, to make sure everything...
Definition: SkillDetailsTreeWidget.cpp:208
SkillExecutionID.h
armarx::memory
Brief description of class memory.
Definition: memory.h:38
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::skills::SkillID::isProviderSpecified
bool isProviderSpecified() const
Definition: SkillID.cpp:90
NLohmannJSONConverter.h
armarx::skills::gui::SkillDetailsTreeWidget::updateContents
void updateContents(skills::SkillID const &skillId, skills::SkillDescription const &descr)
Definition: SkillDetailsTreeWidget.cpp:46
armarx::skills::gui::SkillDetailsTreeWidget::reloadLastExecutionParameters
void reloadLastExecutionParameters()
Definition: SkillDetailsTreeWidget.cpp:241
armarx::skills::gui::SkillManagerWrapper::Snapshot
Definition: SkillManagerWrapper.h:82
armarx::skills::gui::SkillDetailsTreeWidget::getShownId
std::optional< skills::SkillID > getShownId()
Definition: SkillDetailsTreeWidget.cpp:33
armarx::skills::gui::SkillDetailsTreeWidget::copyCurrentSkillID
void copyCurrentSkillID()
Definition: SkillDetailsTreeWidget.cpp:309
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
AronTreeWidgetController.h
armarx::skills::gui::SkillDetailsTreeWidget::copyCurrentConfig
void copyCurrentConfig()
Definition: SkillDetailsTreeWidget.cpp:296
armarx::skills::gui
Definition: PeriodicUpdateWidget.cpp:11
armarx::skills::gui::SkillDetailsTreeWidget::getConfigAsAron
aron::data::DictPtr getConfigAsAron()
Definition: SkillDetailsTreeWidget.cpp:285
armarx::armem::server::ltm::util::mongodb::detail::update
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition: mongodb.cpp:68
armarx::skills::SkillDescription::rootProfileDefaults
aron::data::DictPtr rootProfileDefaults
Definition: SkillDescription.h:21
armarx::skills::gui::SkillDetailsTreeWidget::disconnectGui
void disconnectGui()
Definition: SkillDetailsTreeWidget.cpp:91
armarx::skills::gui::SkillDetailsTreeWidget::updated
void updated(const skills::SkillID shownSkill)
armarx::skills::gui::SkillDetailsTreeWidget::resetWidget
void resetWidget()
Definition: SkillDetailsTreeWidget.cpp:362
armarx::aron::data::DictPtr
std::shared_ptr< Dict > DictPtr
Definition: Dict.h:41
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
Logging.h
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::skills::SkillDescription::parametersType
aron::type::ObjectPtr parametersType
Definition: SkillDescription.h:23
armarx::skills::SkillID
Definition: SkillID.h:14
armarx::skills::SkillID::isFullySpecified
bool isFullySpecified() const
Definition: SkillID.cpp:78
armarx::skills::gui::SkillDetailsTreeWidget::pasteCurrentConfig
void pasteCurrentConfig()
Definition: SkillDetailsTreeWidget.cpp:321
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx::skills::gui::MemoryCommunicatorBase
Definition: MemoryCommunicatorBase.h:14