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
00030
00031 #include <mapviz/select_service_dialog.h>
00032
00033 #include <QCloseEvent>
00034 #include <QHBoxLayout>
00035 #include <QLabel>
00036 #include <QLineEdit>
00037 #include <QListWidget>
00038 #include <QMessageBox>
00039 #include <QPushButton>
00040 #include <QTimerEvent>
00041 #include <QVBoxLayout>
00042
00043 #include <rosapi/Services.h>
00044 #include <rosapi/ServicesForType.h>
00045 #if QT_VERSION >= 0x050000
00046 #include <QtWidgets/QMessageBox>
00047 #else
00048 #include <QtGui/QMessageBox>
00049 #endif
00050
00051 namespace mapviz
00052 {
00053 void ServiceUpdaterThread::run()
00054 {
00055 ros::ServiceClient client;
00056
00057 if (allowed_datatype_.empty())
00058 {
00059 client = nh_.serviceClient<rosapi::Services>("/rosapi/services");
00060 }
00061 else
00062 {
00063 client = nh_.serviceClient<rosapi::ServicesForType>("/rosapi/services_for_type");
00064 }
00065
00066 if (!client.waitForExistence(ros::Duration(1)))
00067 {
00068
00069 Q_EMIT fetchingFailed(tr("Unable to list ROS services. Is rosapi_node running?"));
00070 return;
00071 }
00072
00073 if (allowed_datatype_.empty())
00074 {
00075 rosapi::Services srv;
00076
00077 ROS_DEBUG("Listing all services.");
00078 if (client.call(srv))
00079 {
00080 Q_EMIT servicesFetched(srv.response.services);
00081 }
00082 }
00083 else {
00084 rosapi::ServicesForType srv;
00085 srv.request.type = allowed_datatype_;
00086
00087 ROS_DEBUG("Listing services for type %s", srv.request.type.c_str());
00088 if (client.call(srv))
00089 {
00090 Q_EMIT servicesFetched(srv.response.services);
00091 }
00092 else
00093 {
00094
00095
00096
00097 Q_EMIT fetchingFailed(tr("Unable to list ROS services. You may have " \
00098 "dead nodes; try running \"rosnode cleanup\"."));
00099 }
00100 }
00101 }
00102
00103 std::string SelectServiceDialog::selectService(const std::string& datatype, QWidget* parent)
00104 {
00105 SelectServiceDialog dialog(datatype, parent);
00106 dialog.setDatatypeFilter(datatype);
00107 if (dialog.exec() == QDialog::Accepted) {
00108 return dialog.selectedService();
00109 } else {
00110 return "";
00111 }
00112 }
00113
00114 SelectServiceDialog::SelectServiceDialog(const std::string& datatype, QWidget* parent)
00115 :
00116 QDialog(parent),
00117 allowed_datatype_(datatype),
00118 cancel_button_(new QPushButton("&Cancel")),
00119 list_widget_(new QListWidget()),
00120 name_filter_(new QLineEdit()),
00121 ok_button_(new QPushButton("&Ok"))
00122 {
00123 QHBoxLayout *filter_box = new QHBoxLayout();
00124 filter_box->addWidget(new QLabel("Filter:"));
00125 filter_box->addWidget(name_filter_);
00126
00127 QHBoxLayout *button_box = new QHBoxLayout();
00128 button_box->addStretch(1);
00129 button_box->addWidget(cancel_button_);
00130 button_box->addWidget(ok_button_);
00131
00132 QVBoxLayout *vbox = new QVBoxLayout();
00133 vbox->addWidget(list_widget_);
00134 vbox->addLayout(filter_box);
00135 vbox->addLayout(button_box);
00136 setLayout(vbox);
00137
00138
00139
00140 qRegisterMetaType<ServiceStringVector>("ServiceStringVector");
00141
00142 connect(ok_button_, SIGNAL(clicked(bool)),
00143 this, SLOT(accept()));
00144 connect(cancel_button_, SIGNAL(clicked(bool)),
00145 this, SLOT(reject()));
00146 connect(name_filter_, SIGNAL(textChanged(const QString &)),
00147 this, SLOT(updateDisplayedServices()));
00148
00149 ok_button_->setDefault(true);
00150
00151 setWindowTitle("Select service...");
00152
00153 fetch_services_timer_id_ = startTimer(5000);
00154 fetchServices();
00155 }
00156
00157 SelectServiceDialog::~SelectServiceDialog()
00158 {
00159 if (worker_thread_)
00160 {
00161
00162
00163
00164
00165 worker_thread_->wait(5000);
00166 if (worker_thread_->isRunning())
00167 {
00168 worker_thread_->terminate();
00169 worker_thread_->wait(2000);
00170 }
00171 }
00172 }
00173
00174 void SelectServiceDialog::fetchServices()
00175 {
00176
00177
00178 if (!worker_thread_ || worker_thread_->isFinished())
00179 {
00180 worker_thread_.reset(new ServiceUpdaterThread(nh_, allowed_datatype_, this));
00181 QObject::connect(worker_thread_.get(),
00182 SIGNAL(servicesFetched(ServiceStringVector)),
00183 this,
00184 SLOT(updateKnownServices(ServiceStringVector)));
00185 QObject::connect(worker_thread_.get(),
00186 SIGNAL(fetchingFailed(const QString)),
00187 this,
00188 SLOT(displayUpdateError(const QString)));
00189 worker_thread_->start();
00190 }
00191 }
00192
00193 void SelectServiceDialog::updateKnownServices(ServiceStringVector services)
00194 {
00195 known_services_ = services;
00196 updateDisplayedServices();
00197 }
00198
00199 void SelectServiceDialog::displayUpdateError(const QString error_msg)
00200 {
00201 killTimer(fetch_services_timer_id_);
00202 QMessageBox mbox(this->parentWidget());
00203 mbox.setIcon(QMessageBox::Warning);
00204 mbox.setText(error_msg);
00205 mbox.exec();
00206 }
00207
00208 std::vector<std::string> SelectServiceDialog::filterServices()
00209 {
00210 std::vector<std::string> filtered_services;
00211
00212 QString filter_text = name_filter_->text();
00213
00214 Q_FOREACH(const std::string& service, known_services_)
00215 {
00216 if (QString::fromStdString(service).contains(filter_text, Qt::CaseInsensitive))
00217 {
00218 filtered_services.push_back(service);
00219 }
00220 }
00221
00222 return filtered_services;
00223 }
00224
00225 void SelectServiceDialog::updateDisplayedServices()
00226 {
00227 std::vector<std::string> next_displayed_services = filterServices();
00228
00229
00230
00231
00232
00233
00234 std::set<std::string> prev_names;
00235 for (size_t i = 0; i < displayed_services_.size(); i++) {
00236 prev_names.insert(displayed_services_[i]);
00237 }
00238
00239 std::set<std::string> next_names;
00240 for (size_t i = 0; i < next_displayed_services.size(); i++) {
00241 next_names.insert(next_displayed_services[i]);
00242 }
00243
00244 std::set<std::string> added_names;
00245 std::set_difference(next_names.begin(), next_names.end(),
00246 prev_names.begin(), prev_names.end(),
00247 std::inserter(added_names, added_names.end()));
00248
00249 std::set<std::string> removed_names;
00250 std::set_difference(prev_names.begin(), prev_names.end(),
00251 next_names.begin(), next_names.end(),
00252 std::inserter(removed_names, removed_names.end()));
00253
00254
00255 size_t removed = 0;
00256 for (size_t i = 0; i < displayed_services_.size(); i++) {
00257 if (removed_names.count(displayed_services_[i]) == 0) {
00258 continue;
00259 }
00260
00261 QListWidgetItem *item = list_widget_->takeItem(i - removed);
00262 delete item;
00263 removed++;
00264 }
00265
00266
00267 for (size_t i = 0; i < next_displayed_services.size(); i++) {
00268 if (added_names.count(next_displayed_services[i]) == 0) {
00269 continue;
00270 }
00271
00272 list_widget_->insertItem(i, QString::fromStdString(next_displayed_services[i]));
00273 if (list_widget_->count() == 1) {
00274 list_widget_->setCurrentRow(0);
00275 }
00276 }
00277
00278 displayed_services_.swap(next_displayed_services);
00279 }
00280
00281 void SelectServiceDialog::setDatatypeFilter(const std::string& datatype)
00282 {
00283 allowed_datatype_ = datatype;
00284 updateDisplayedServices();
00285 }
00286
00287 std::string SelectServiceDialog::selectedService() const
00288 {
00289 QModelIndex qt_selection = list_widget_->selectionModel()->currentIndex();
00290
00291 if (qt_selection.isValid()) {
00292 int row = qt_selection.row();
00293 if (row < static_cast<int>(displayed_services_.size())) {
00294 return displayed_services_[row];
00295 }
00296 }
00297
00298 return "";
00299 }
00300
00301 void SelectServiceDialog::timerEvent(QTimerEvent* event)
00302 {
00303 if (event->timerId() == fetch_services_timer_id_) {
00304 fetchServices();
00305 }
00306 }
00307
00308 void SelectServiceDialog::closeEvent(QCloseEvent* event)
00309 {
00310
00311 killTimer(fetch_services_timer_id_);
00312 QDialog::closeEvent(event);
00313 }
00314 }