ControlDevicesWidget.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * \package RobotAPI::gui-plugins::RobotUnitPlugin
17 * \author Raphael Grimm ( raphael dot grimm at kit dot edu )
18 * \date 2017
19 * \copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
23
24#include <QCheckBox>
25
26#include "StyleSheets.h"
27
28namespace armarx
29{
31 RobotUnitWidgetTemplateBase("ControlDevicesWidget", parent)
32 {
33 ui->treeWidget->setColumnCount(8);
34 QTreeWidgetItem* head = ui->treeWidget->headerItem();
35 head->setText(idxName, "Name");
36 head->setText(idxTags, "Tags");
37 head->setText(idxMode, "Mode");
38 head->setText(idxHWMode, "HardwareMode");
39 head->setText(idxAct, "Act");
40 head->setText(idxReq, "Req");
41 head->setText(idxType, "Target Type");
42 head->setText(idxVal, "Target Value");
43
44 head->setToolTip(
45 idxName,
46 "The control device's name (green: ok, red: missmatch between requested and active "
47 "mode, orange: active/requested device not found in the displayed list)");
48 head->setToolTip(idxTags, "The control device's tags");
49 head->setToolTip(idxMode, "The control device's control mode");
50 head->setToolTip(idxHWMode, "The control device's hardware control mode");
51 head->setToolTip(idxAct,
52 "Whether the control mode is active (green: ok, red: missmatch between "
53 "requested and active mode)");
54 head->setToolTip(idxReq,
55 "Whether the control mode is requested (green: ok, red: missmatch between "
56 "requested and active mode)");
57 head->setToolTip(idxType, "The control mode's target type");
58 head->setToolTip(idxVal, "The control mode's target value");
59
60 ui->treeWidget->setColumnWidth(idxName, 150);
61 ui->treeWidget->setColumnWidth(idxTags, 100);
62 ui->treeWidget->setColumnWidth(idxMode, 225);
63 ui->treeWidget->setColumnWidth(idxHWMode, 110);
64 ui->treeWidget->setColumnWidth(idxAct, 40);
65 ui->treeWidget->setColumnWidth(idxReq, 40);
66 ui->treeWidget->setColumnWidth(idxType, 350);
67 ui->treeWidget->header()->setResizeMode(idxAct, QHeaderView::Fixed);
68 ui->treeWidget->header()->setResizeMode(idxReq, QHeaderView::Fixed);
69 }
70
75
76 void
77 ControlDevicesWidget::controlDeviceStatusChanged(const ControlDeviceStatusSeq& allStatus)
78 {
79 std::unique_lock<std::recursive_timed_mutex> guard{mutex, std::defer_lock};
80 if (!guard.try_lock_for(std::chrono::microseconds(100)))
81 {
82 return;
83 }
84 for (const auto& status : allStatus)
85 {
86 if (statusUpdates[status.deviceName].timestampUSec < status.timestampUSec)
87 {
88 statusUpdates[status.deviceName] = status;
89 if (doMetaCall)
90 {
91 QMetaObject::invokeMethod(this, "updateContent", Qt::QueuedConnection);
92 }
93 }
94 }
95 }
96
97 void
99 {
100 entries.clear();
101 statusUpdates.clear();
102 resetData.clear();
103 }
104
105 void
107 {
108 for (const auto& pair : statusUpdates)
109 {
110 update(pair.second);
111 }
112 statusUpdates.clear();
113 }
114
115 void
117 {
118 auto temp = robotUnit->getControlDeviceDescriptions();
119 {
120 std::unique_lock<std::recursive_timed_mutex> guard{mutex};
121 resetData = std::move(temp);
122 }
123 }
124
125 bool
127 {
128 if (resetData.empty())
129 {
130 return true;
131 }
132 add(resetData.back());
133 resetData.pop_back();
134 return false;
135 }
136
137 void
138 ControlDevicesWidget::add(const ControlDeviceDescription& desc)
139 {
140 std::unique_lock<std::recursive_timed_mutex> guard{mutex};
141 if (entries.count(desc.deviceName))
142 {
143 return;
144 }
145 entries[desc.deviceName] = new ControlDevicesWidgetEntry(*this, *(ui->treeWidget), desc);
146 }
147
148 void
149 ControlDevicesWidget::update(const ControlDeviceStatus& status)
150 {
151 std::unique_lock<std::recursive_timed_mutex> guard{mutex};
152 if (!robotUnit || !robotUnit->isRunning())
153 {
154 return;
155 }
156 if (!entries.count(status.deviceName))
157 {
158 add(robotUnit->getControlDeviceDescription(status.deviceName));
159 }
160 entries.at(status.deviceName)->update(status);
161 }
162
164 QTreeWidget& treeWidget,
165 const ControlDeviceDescription& desc) :
166 QObject{&parent}
167 {
168 header = new QTreeWidgetItem;
169 treeWidget.addTopLevelItem(header);
170 header->setText(ControlDevicesWidget::idxName, QString::fromStdString(desc.deviceName));
171 //tags
172 {
173 QCheckBox* boxTags = new QCheckBox{QString::number(desc.tags.size()) + " Tags"};
174 treeWidget.setItemWidget(header, ControlDevicesWidget::idxTags, boxTags);
175 boxTags->setStyleSheet(checkboxStyleSheet());
176 boxTags->setChecked(false);
177 connect(boxTags, SIGNAL(clicked(bool)), this, SLOT(hideTagList(bool)));
178 for (const auto& tag : desc.tags)
179 {
180 QTreeWidgetItem* child = new QTreeWidgetItem{{QString::fromStdString(tag)}};
181 treeWidget.addTopLevelItem(child);
182 tags.emplace_back(child);
183 }
184 }
185 for (const auto& nameToType : desc.contolModeToTargetType)
186 {
187 ControllerEntry& subEntry = subEntries[nameToType.first];
188 subEntry.child = new QTreeWidgetItem;
189 header->addChild(subEntry.child);
190 subEntry.child->setText(ControlDevicesWidget::idxMode,
191 QString::fromStdString(nameToType.first));
192 subEntry.child->setText(ControlDevicesWidget::idxHWMode,
193 QString::fromStdString(nameToType.second.hardwareControlMode));
194 subEntry.child->setText(ControlDevicesWidget::idxAct, " ");
195 subEntry.child->setText(ControlDevicesWidget::idxReq, " ");
196 subEntry.child->setText(ControlDevicesWidget::idxType,
197 QString::fromStdString(nameToType.second.targetType));
198 subEntry.value = new VariantWidget;
199 treeWidget.setItemWidget(subEntry.child, ControlDevicesWidget::idxVal, subEntry.value);
200 }
201 }
202
203 void
204 ControlDevicesWidgetEntry::update(const ControlDeviceStatus& status)
205 {
206 auto colorNew = (status.activeControlMode == status.requestedControlMode) ? green() : red();
207 bool newDevsNotFound = false;
208 if (activeMode != status.activeControlMode)
209 {
210 if (subEntries.count(activeMode))
211 {
212 subEntries.at(activeMode).child->setText(ControlDevicesWidget::idxAct, " ");
213 subEntries.at(activeMode)
214 .child->setBackgroundColor(ControlDevicesWidget::idxAct, transparent());
215 }
216 activeMode = status.activeControlMode;
217 if (subEntries.count(activeMode))
218 {
219 newDevsNotFound = true;
220 subEntries.at(activeMode).child->setText(ControlDevicesWidget::idxAct, "X");
221 }
222 }
223 if (requestedMode != status.requestedControlMode)
224 {
225 if (subEntries.count(requestedMode))
226 {
227 subEntries.at(requestedMode).child->setText(ControlDevicesWidget::idxReq, " ");
228 subEntries.at(requestedMode)
229 .child->setBackgroundColor(ControlDevicesWidget::idxReq, transparent());
230 }
231 requestedMode = status.requestedControlMode;
232 if (subEntries.count(requestedMode))
233 {
234 newDevsNotFound = true;
235 subEntries.at(requestedMode).child->setText(ControlDevicesWidget::idxReq, "X");
236 }
237 }
238 //color
239 {
240 //set the color here, since active may change without requested changen (or the other way) -> above there is no update
241 if (subEntries.count(requestedMode))
242 {
243 subEntries.at(requestedMode)
244 .child->setBackgroundColor(ControlDevicesWidget::idxReq, colorNew);
245 }
246 if (subEntries.count(activeMode))
247 {
248 subEntries.at(activeMode)
249 .child->setBackgroundColor(ControlDevicesWidget::idxAct, colorNew);
250 }
251 header->setBackgroundColor(ControlDevicesWidget::idxName,
252 newDevsNotFound ? orange() : colorNew);
253 }
254 for (const auto& pair : status.controlTargetValues)
255 {
256 if (subEntries.count(pair.first))
257 {
258 subEntries.at(pair.first).value->update(pair.second);
259 subEntries.at(pair.first).value->layout()->setContentsMargins(0, 0, 0, 0);
260 }
261 }
262 }
263
264 bool
266 {
267 return header->text(ControlDevicesWidget::idxName).contains(name, Qt::CaseInsensitive);
268 }
269
270 bool
272 {
273 for (const auto& tagit : tags)
274 {
275 if (tagit->text(ControlDevicesWidget::idxTags).contains(tag, Qt::CaseInsensitive))
276 {
277 return true;
278 }
279 }
280 return false;
281 }
282
283 std::set<QTreeWidgetItem*>
285 {
286 std::set<QTreeWidgetItem*> hits;
287 for (const auto& pair : subEntries)
288 {
289 if (pair.second.child->text(ControlDevicesWidget::idxMode)
290 .contains(mode, Qt::CaseInsensitive))
291 {
292 hits.emplace(pair.second.child);
293 }
294 }
295 return hits;
296 }
297
298 std::set<QTreeWidgetItem*>
300 {
301 std::set<QTreeWidgetItem*> hits;
302 for (const auto& pair : subEntries)
303 {
304 if (pair.second.child->text(ControlDevicesWidget::idxAct)
305 .contains(state, Qt::CaseInsensitive))
306 {
307 hits.emplace(pair.second.child);
308 }
309 }
310 return hits;
311 }
312
313 std::set<QTreeWidgetItem*>
315 {
316 std::set<QTreeWidgetItem*> hits;
317 for (const auto& pair : subEntries)
318 {
319 if (pair.second.child->text(ControlDevicesWidget::idxReq)
320 .contains(state, Qt::CaseInsensitive))
321 {
322 hits.emplace(pair.second.child);
323 }
324 }
325 return hits;
326 }
327
328 std::set<QTreeWidgetItem*>
330 {
331 std::set<QTreeWidgetItem*> hits;
332 for (const auto& pair : subEntries)
333 {
334 if (pair.second.child->text(ControlDevicesWidget::idxType)
335 .contains(type, Qt::CaseInsensitive))
336 {
337 hits.emplace(pair.second.child);
338 }
339 }
340 return hits;
341 }
342
343 void
345 {
346 if (!vis)
347 {
348 hideTagList(true);
349 }
350 header->setHidden(!vis);
351 }
352
353 void
354 ControlDevicesWidgetEntry::setChildVis(bool vis, std::set<QTreeWidgetItem*> children)
355 {
356 for (const auto& pair : subEntries)
357 {
358 if (children.count(pair.second.child))
359 {
360 pair.second.child->setHidden(!vis);
361 }
362 else
363 {
364 pair.second.child->setHidden(vis);
365 }
366 }
367 }
368
369 void
370 ControlDevicesWidgetEntry::hideTagList(bool hide)
371 {
372 for (QTreeWidgetItem* tag : tags)
373 {
374 tag->setHidden(hide);
375 }
376 }
377} // namespace armarx
std::set< QTreeWidgetItem * > isActiveState(const QString &state)
void setChildVis(bool vis, std::set< QTreeWidgetItem * > children)
std::set< QTreeWidgetItem * > matchMode(const QString &mode)
std::set< QTreeWidgetItem * > isRequestedState(const QString &state)
std::set< QTreeWidgetItem * > matchTargetType(const QString &type)
ControlDevicesWidgetEntry(ControlDevicesWidget &parent, QTreeWidget &treeWidget, const ControlDeviceDescription &desc)
void update(const ControlDeviceStatus &status)
void controlDeviceStatusChanged(const ControlDeviceStatusSeq &allStatus)
RobotUnitInterfacePrx robotUnit
std::recursive_timed_mutex mutex
This file offers overloads of toIce() and fromIce() functions for STL container types.
QColor green()
Definition StyleSheets.h:72
QColor transparent()
Definition StyleSheets.h:90
QString checkboxStyleSheet()
Definition StyleSheets.h:31
QColor red()
Definition StyleSheets.h:78
QColor orange()
Definition StyleSheets.h:84