Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <mapviz/select_topic_dialog.h>
00030
00031 #include <algorithm>
00032
00033 #include <QListWidget>
00034 #include <QLineEdit>
00035 #include <QVBoxLayout>
00036 #include <QHBoxLayout>
00037 #include <QPushButton>
00038 #include <QLabel>
00039 #include <QTimerEvent>
00040
00041 namespace mapviz
00042 {
00043 ros::master::TopicInfo SelectTopicDialog::selectTopic(
00044 const std::string &datatype,
00045 QWidget *parent)
00046 {
00047 std::vector<std::string> datatypes;
00048 datatypes.push_back(datatype);
00049 return selectTopic(datatypes, parent);
00050 }
00051
00052 ros::master::TopicInfo SelectTopicDialog::selectTopic(
00053 const std::string &datatype1,
00054 const std::string &datatype2,
00055 QWidget *parent)
00056 {
00057 std::vector<std::string> datatypes;
00058 datatypes.push_back(datatype1);
00059 datatypes.push_back(datatype2);
00060 return selectTopic(datatypes, parent);
00061 }
00062
00063 ros::master::TopicInfo SelectTopicDialog::selectTopic(
00064 const std::vector<std::string> &datatypes,
00065 QWidget *parent)
00066 {
00067 SelectTopicDialog dialog(parent);
00068 dialog.allowMultipleTopics(false);
00069 dialog.setDatatypeFilter(datatypes);
00070 if (dialog.exec() == QDialog::Accepted) {
00071 return dialog.selectedTopic();
00072 } else {
00073 return ros::master::TopicInfo();
00074 }
00075 }
00076
00077 std::vector<ros::master::TopicInfo> SelectTopicDialog::selectTopics(
00078 const std::string &datatype,
00079 QWidget *parent)
00080 {
00081 std::vector<std::string> datatypes;
00082 datatypes.push_back(datatype);
00083 return selectTopics(datatypes, parent);
00084 }
00085
00086 std::vector<ros::master::TopicInfo> SelectTopicDialog::selectTopics(
00087 const std::string &datatype1,
00088 const std::string &datatype2,
00089 QWidget *parent)
00090 {
00091 std::vector<std::string> datatypes;
00092 datatypes.push_back(datatype1);
00093 datatypes.push_back(datatype2);
00094 return selectTopics(datatypes, parent);
00095 }
00096
00097 std::vector<ros::master::TopicInfo> SelectTopicDialog::selectTopics(
00098 const std::vector<std::string> &datatypes,
00099 QWidget *parent)
00100 {
00101 SelectTopicDialog dialog(parent);
00102 dialog.allowMultipleTopics(true);
00103 dialog.setDatatypeFilter(datatypes);
00104 if (dialog.exec() == QDialog::Accepted) {
00105 return dialog.selectedTopics();
00106 } else {
00107 return std::vector<ros::master::TopicInfo>();
00108 }
00109 }
00110
00111 SelectTopicDialog::SelectTopicDialog(QWidget *parent)
00112 :
00113 ok_button_(new QPushButton("&Ok")),
00114 cancel_button_(new QPushButton("&Cancel")),
00115 list_widget_(new QListWidget()),
00116 name_filter_(new QLineEdit())
00117 {
00118 QHBoxLayout *filter_box = new QHBoxLayout();
00119 filter_box->addWidget(new QLabel("Filter:"));
00120 filter_box->addWidget(name_filter_);
00121
00122 QHBoxLayout *button_box = new QHBoxLayout();
00123 button_box->addStretch(1);
00124 button_box->addWidget(cancel_button_);
00125 button_box->addWidget(ok_button_);
00126
00127 QVBoxLayout *vbox = new QVBoxLayout();
00128 vbox->addWidget(list_widget_);
00129 vbox->addLayout(filter_box);
00130 vbox->addLayout(button_box);
00131 setLayout(vbox);
00132
00133 connect(ok_button_, SIGNAL(clicked(bool)),
00134 this, SLOT(accept()));
00135 connect(cancel_button_, SIGNAL(clicked(bool)),
00136 this, SLOT(reject()));
00137 connect(name_filter_, SIGNAL(textChanged(const QString &)),
00138 this, SLOT(updateDisplayedTopics()));
00139
00140 ok_button_->setDefault(true);
00141
00142 allowMultipleTopics(false);
00143 setWindowTitle("Select topics...");
00144
00145 fetch_topics_timer_id_ = startTimer(1000);
00146 fetchTopics();
00147 }
00148
00149 void SelectTopicDialog::timerEvent(QTimerEvent *event)
00150 {
00151 if (event->timerId() == fetch_topics_timer_id_) {
00152 fetchTopics();
00153 }
00154 }
00155
00156 void SelectTopicDialog::closeEvent(QCloseEvent *event)
00157 {
00158
00159 killTimer(fetch_topics_timer_id_);
00160 QDialog::closeEvent(event);
00161 }
00162
00163 void SelectTopicDialog::allowMultipleTopics(
00164 bool allow)
00165 {
00166 if (allow) {
00167 list_widget_->setSelectionMode(QAbstractItemView::MultiSelection);
00168 } else {
00169 list_widget_->setSelectionMode(QAbstractItemView::SingleSelection);
00170 }
00171 }
00172
00173 void SelectTopicDialog::setDatatypeFilter(
00174 const std::vector<std::string> &datatypes)
00175 {
00176 allowed_datatypes_.clear();
00177 for (size_t i = 0; i < datatypes.size(); i++) {
00178 allowed_datatypes_.insert(datatypes[i]);
00179 }
00180 updateDisplayedTopics();
00181 }
00182
00183 ros::master::TopicInfo SelectTopicDialog::selectedTopic() const
00184 {
00185 std::vector<ros::master::TopicInfo> selection = selectedTopics();
00186 if (selection.empty()) {
00187 return ros::master::TopicInfo();
00188 } else {
00189 return selection.front();
00190 }
00191 }
00192
00193 std::vector<ros::master::TopicInfo> SelectTopicDialog::selectedTopics() const
00194 {
00195 QModelIndexList qt_selection = list_widget_->selectionModel()->selectedIndexes();
00196
00197 std::vector<ros::master::TopicInfo> selection;
00198 selection.resize(qt_selection.size());
00199 for (int i = 0; i < qt_selection.size(); i++) {
00200 if (!qt_selection[i].isValid()) {
00201 continue;
00202 }
00203
00204 int row = qt_selection[i].row();
00205 if (row < 0 || static_cast<size_t>(row) >= displayed_topics_.size()) {
00206 continue;
00207 }
00208
00209 selection[i] = displayed_topics_[row];
00210 }
00211
00212 return selection;
00213 }
00214
00215 static bool topicSort(const ros::master::TopicInfo &info1,
00216 const ros::master::TopicInfo &info2)
00217 {
00218 return info1.name < info2.name;
00219 }
00220
00221 void SelectTopicDialog::fetchTopics()
00222 {
00223 ros::master::getTopics(known_topics_);
00224 std::sort(known_topics_.begin(), known_topics_.end(), topicSort);
00225 updateDisplayedTopics();
00226 }
00227
00228 std::vector<ros::master::TopicInfo> SelectTopicDialog::filterTopics(
00229 const std::vector<ros::master::TopicInfo> &topics) const
00230 {
00231 QString topic_filter = name_filter_->text();
00232 std::vector<ros::master::TopicInfo> filtered;
00233
00234 for (size_t i = 0; i < topics.size(); i++) {
00235 if (!allowed_datatypes_.empty() &&
00236 allowed_datatypes_.count(topics[i].datatype) == 0) {
00237 continue;
00238 }
00239
00240 QString topic_name = QString::fromStdString(topics[i].name);
00241 if (!topic_filter.isEmpty() &&
00242 !topic_name.contains(topic_filter, Qt::CaseInsensitive)) {
00243 continue;
00244 }
00245
00246 filtered.push_back(topics[i]);
00247 }
00248
00249 return filtered;
00250 }
00251
00252 void SelectTopicDialog::updateDisplayedTopics()
00253 {
00254 std::vector<ros::master::TopicInfo> next_displayed_topics = filterTopics(known_topics_);
00255
00256
00257
00258
00259
00260
00261 std::set<std::string> prev_names;
00262 for (size_t i = 0; i < displayed_topics_.size(); i++) {
00263 prev_names.insert(displayed_topics_[i].name);
00264 }
00265
00266 std::set<std::string> next_names;
00267 for (size_t i = 0; i < next_displayed_topics.size(); i++) {
00268 next_names.insert(next_displayed_topics[i].name);
00269 }
00270
00271 std::set<std::string> added_names;
00272 std::set_difference(next_names.begin(), next_names.end(),
00273 prev_names.begin(), prev_names.end(),
00274 std::inserter(added_names, added_names.end()));
00275
00276 std::set<std::string> removed_names;
00277 std::set_difference(prev_names.begin(), prev_names.end(),
00278 next_names.begin(), next_names.end(),
00279 std::inserter(removed_names, removed_names.end()));
00280
00281
00282 size_t removed = 0;
00283 for (size_t i = 0; i < displayed_topics_.size(); i++) {
00284 if (removed_names.count(displayed_topics_[i].name) == 0) {
00285 continue;
00286 }
00287
00288 QListWidgetItem *item = list_widget_->takeItem(i - removed);
00289 delete item;
00290 removed++;
00291 }
00292
00293
00294 for (size_t i = 0; i < next_displayed_topics.size(); i++) {
00295 if (added_names.count(next_displayed_topics[i].name) == 0) {
00296 continue;
00297 }
00298
00299 list_widget_->insertItem(i, QString::fromStdString(next_displayed_topics[i].name));
00300 if (list_widget_->count() == 1) {
00301 list_widget_->setCurrentRow(0);
00302 }
00303 }
00304
00305 displayed_topics_.swap(next_displayed_topics);
00306 }
00307 }