moveit2
The MoveIt Motion Planning Framework for ROS 2.
double_list_widget.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Dave Coleman */
36 
37 #include <QFormLayout>
38 #include <QGroupBox>
39 #include <QHBoxLayout>
40 #include <QHeaderView>
41 #include <QLabel>
42 #include <QLineEdit>
43 #include <QMessageBox>
44 #include <QPushButton>
45 #include <QString>
46 #include <QTableWidget>
47 #include <QVBoxLayout>
49 
50 namespace moveit_setup
51 {
52 // ******************************************************************************************
53 //
54 // ******************************************************************************************
55 DoubleListWidget::DoubleListWidget(QWidget* parent, const QString& long_name, const QString& short_name,
56  bool add_ok_cancel)
57  : QWidget(parent), long_name_(long_name), short_name_(short_name)
58 {
59  // Basic widget container
60  QVBoxLayout* layout = new QVBoxLayout();
61 
62  // Label ------------------------------------------------
63  title_ = new QLabel("", this); // specify the title from the parent widget
64  QFont group_title_font(QFont().defaultFamily(), 12, QFont::Bold);
65  title_->setFont(group_title_font);
66  layout->addWidget(title_);
67 
68  // Double selection lists -------------------------------
69  QHBoxLayout* hlayout = new QHBoxLayout();
70 
71  // Left column -------------------------------------------
72  QVBoxLayout* column1 = new QVBoxLayout();
73 
74  // Label
75  column1_label_ = new QLabel(QString("Available ").append(short_name_).append('s'), this);
76  column1->addWidget(column1_label_);
77 
78  // Table
79  data_table_ = new QTableWidget(this);
80  data_table_->setColumnCount(1);
81  data_table_->setSortingEnabled(true);
82  column1->addWidget(data_table_);
83  connect(data_table_->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
84  SLOT(previewSelectedLeft(QItemSelection, QItemSelection)));
85 
86  // Table headers
87  QStringList data_header_list;
88  data_header_list.append(QString(" Names").prepend(short_name_));
89  data_table_->setHorizontalHeaderLabels(data_header_list);
90  data_table_->horizontalHeader()->setDefaultAlignment(Qt::AlignHCenter);
91 
92  // Add layouts
93  hlayout->addLayout(column1);
94 
95  // Center column ------------------------------------------
96  QVBoxLayout* column2 = new QVBoxLayout();
97  column2->setSizeConstraint(QLayout::SetFixedSize); // constraint it
98 
99  // Right Arrow Button
100  QPushButton* btn_right = new QPushButton(">", this);
101  btn_right->setMaximumSize(25, 80);
102  connect(btn_right, SIGNAL(clicked()), this, SLOT(selectDataButtonClicked()));
103  column2->addWidget(btn_right);
104 
105  // Left Arrow Button
106  QPushButton* btn_left = new QPushButton("<", this);
107  btn_left->setMaximumSize(25, 80);
108  connect(btn_left, SIGNAL(clicked()), this, SLOT(deselectDataButtonClicked()));
109  column2->addWidget(btn_left);
110 
111  // Add layouts
112  hlayout->addLayout(column2);
113 
114  // Right column -------------------------------------------
115  QVBoxLayout* column3 = new QVBoxLayout();
116 
117  // Label
118  column2_label_ = new QLabel(QString("Selected ").append(short_name_).append("s"), this);
119  column3->addWidget(column2_label_);
120 
121  // Table
122  selected_data_table_ = new QTableWidget(this);
123  selected_data_table_->setColumnCount(1);
124  selected_data_table_->setSortingEnabled(true);
125  column3->addWidget(selected_data_table_);
126  connect(selected_data_table_->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
127  SLOT(previewSelectedRight(QItemSelection, QItemSelection)));
128 
129  // Table Headers (use same)
130  selected_data_table_->setHorizontalHeaderLabels(data_header_list);
131 
132  // Add layouts
133  hlayout->addLayout(column3);
134 
135  // End Double Selection List ---------------------------------
136  layout->addLayout(hlayout);
137 
138  if (add_ok_cancel)
139  {
140  // Button controls -------------------------------------------
141  QHBoxLayout* controls_layout = new QHBoxLayout();
142  controls_layout->setContentsMargins(0, 25, 0, 15);
143 
144  // Spacer
145  controls_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
146 
147  // Save
148  QPushButton* btn_save = new QPushButton("&Save", this);
149  // btn_save->setMaximumWidth( 200 );
150  connect(btn_save, SIGNAL(clicked()), this, SIGNAL(doneEditing()));
151  controls_layout->addWidget(btn_save);
152  controls_layout->setAlignment(btn_save, Qt::AlignRight);
153 
154  // Cancel
155  QPushButton* btn_cancel = new QPushButton("&Cancel", this);
156  // btn_cancel->setMaximumWidth( 200 );
157  connect(btn_cancel, SIGNAL(clicked()), this, SIGNAL(cancelEditing()));
158  controls_layout->addWidget(btn_cancel);
159  controls_layout->setAlignment(btn_cancel, Qt::AlignRight);
160 
161  // Add layout
162  layout->addLayout(controls_layout);
163  }
164 
165  // Finish Layout --------------------------------------------------
166  this->setLayout(layout);
167 }
168 
169 // ******************************************************************************************
170 // Set the left box
171 // ******************************************************************************************
172 void DoubleListWidget::setAvailable(const std::vector<std::string>& items)
173 {
174  setTable(items, data_table_);
175 
176  // Resize both tables
177  data_table_->resizeColumnToContents(0);
178  selected_data_table_->setColumnWidth(0, data_table_->columnWidth(0));
179 }
180 
181 // ******************************************************************************************
182 // Set the right box
183 // ******************************************************************************************
184 void DoubleListWidget::setSelected(const std::vector<std::string>& items)
185 {
187 }
188 
190 {
191  selected_data_table_->clearContents();
192  data_table_->clearContents();
193 }
194 
195 void DoubleListWidget::setColumnNames(const QString& col1, const QString& col2)
196 {
197  column1_label_->setText(col1);
198  column2_label_->setText(col2);
199 }
200 
201 // ******************************************************************************************
202 // Convenience function for reusing set table code
203 // ******************************************************************************************
204 void DoubleListWidget::setTable(const std::vector<std::string>& items, QTableWidget* table)
205 {
206  // Disable Table
207  table->setUpdatesEnabled(false); // prevent table from updating until we are completely done
208  table->setDisabled(true); // make sure we disable it so that the cellChanged event is not called
209  table->clearContents();
210 
211  // Set size of datatable
212  table->setRowCount(items.size());
213 
214  // Loop through every item
215  int row = 0;
216  for (const std::string& item : items)
217  {
218  // This is a hack to prevent a dummy joint from being added. Not really the best place to place this but
219  // here is computationally smart
220  if (item == "ASSUMED_FIXED_ROOT_JOINT")
221  continue;
222 
223  // Create row elements
224  QTableWidgetItem* data_name = new QTableWidgetItem(item.c_str());
225  data_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
226 
227  // Add to table
228  table->setItem(row, 0, data_name);
229 
230  // Increment counter
231  ++row;
232  }
233 
234  table->setRowCount(row);
235 
236  // Re-enable
237  table->setUpdatesEnabled(true); // prevent table from updating until we are completely done
238  table->setDisabled(false); // make sure we disable it so that the cellChanged event is not called
239 }
240 
241 // ******************************************************************************************
242 // Move selected data right
243 // ******************************************************************************************
244 void DoubleListWidget::selectDataButtonClicked()
245 {
246  // Get list of all selected items
247  QList<QTableWidgetItem*> selected = data_table_->selectedItems();
248 
249  // Loop through all selected items
250  for (QTableWidgetItem* item : selected)
251  {
252  std::string name = item->text().toStdString();
253  bool already_exists = false;
254  int row_to_add = 0;
255 
256  // Check if this selected joint is already in the selected joint table
257  for (int r = 0; r < selected_data_table_->rowCount(); ++r)
258  {
259  QTableWidgetItem* item = selected_data_table_->item(r, 0);
260 
261  if (item->text().toStdString() == name)
262  {
263  already_exists = true;
264  break;
265  }
266  row_to_add = r + 1;
267  }
268 
269  // This joint needs to be added to the selected joint table
270  if (!already_exists)
271  {
272  selected_data_table_->setRowCount(selected_data_table_->rowCount() + 1);
273  QTableWidgetItem* new_item = new QTableWidgetItem(name.c_str());
274  new_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
275  selected_data_table_->setItem(row_to_add, 0, new_item);
276  }
277  }
278 
279  Q_EMIT(selectionUpdated());
280 }
281 
282 // ******************************************************************************************
283 // Move selected data left
284 // ******************************************************************************************
285 void DoubleListWidget::deselectDataButtonClicked()
286 {
287  // Get list of joints to be removed from selected list
288  QList<QTableWidgetItem*> deselected = selected_data_table_->selectedItems();
289 
290  // loop through deselect list and remove
291  for (QTableWidgetItem* item : deselected)
292  {
293  selected_data_table_->removeRow(item->row());
294  }
295 
296  Q_EMIT(selectionUpdated());
297 }
298 
299 // ******************************************************************************************
300 // Highlight links of robot for left list
301 // ******************************************************************************************
302 void DoubleListWidget::previewSelectedLeft(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/)
303 {
304  const QList<QTableWidgetItem*> selected_items = data_table_->selectedItems();
305  previewSelected(selected_items);
306 }
307 
308 // ******************************************************************************************
309 // Highlight links of robot for right list
310 // ******************************************************************************************
311 void DoubleListWidget::previewSelectedRight(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/)
312 {
313  const QList<QTableWidgetItem*> selected_items = selected_data_table_->selectedItems();
314  previewSelected(selected_items);
315 }
316 
317 // ******************************************************************************************
318 // Highlight links of robot
319 // ******************************************************************************************
320 void DoubleListWidget::previewSelected(const QList<QTableWidgetItem*>& selected)
321 {
322  // Check that an element was selected
323  if (selected.empty())
324  return;
325 
326  std::vector<std::string> selected_vector;
327 
328  // Convert QList to std vector
329  selected_vector.reserve(selected.size());
330  for (QTableWidgetItem* item : selected)
331  selected_vector.emplace_back(item->text().toStdString());
332 
333  // Send to shared function
334  Q_EMIT(previewSelected(selected_vector));
335 }
336 
337 std::vector<std::string> DoubleListWidget::getSelectedValues() const
338 {
339  std::vector<std::string> values;
340  values.reserve(selected_data_table_->rowCount());
341  for (int i = 0; i < selected_data_table_->rowCount(); ++i)
342  {
343  values.push_back(selected_data_table_->item(i, 0)->text().toStdString());
344  }
345  return values;
346 }
347 
348 } // namespace moveit_setup
void setColumnNames(const QString &col1, const QString &col2)
Set the names of the two columns in the widget.
void doneEditing()
Event sent when this widget is done making data changes and parent widget can save.
void selectionUpdated()
When the set of selected items has changed.
std::vector< std::string > getSelectedValues() const
Return all the values that are in the "selected" subset.
void setTable(const std::vector< std::string > &items, QTableWidget *table)
Convenience function for reusing set table code.
DoubleListWidget(QWidget *parent, const QString &long_name, const QString &short_name, bool add_ok_cancel=true)
Constructor.
void previewSelected(std::vector< std::string >)
Signal to highlight parts of robot.
void cancelEditing()
Event sent when user presses cancel button.
void setAvailable(const std::vector< std::string > &items)
Loads the available data list.
void setSelected(const std::vector< std::string > &items)
Set the right box.
r
Definition: plan.py:56
std::string append(const std::string &left, const std::string &right)
name
Definition: setup.py:7