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