#include #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS #include #include "MainApp.h" #include "Business.h" #include "InfoPanel.h" #include "ClickableLabel.h" #include "Keyboard.h" #include "traces.h" #include #define NAVI_CONFIG_FILEPATH "/etc/naviconfig.ini" #define DEFAULT_TEXT "Select your destination with Yelp !" #define URL_AUTH "https://api.yelp.com/oauth2/token" #define URL_AUTOCOMPLETE "https://api.yelp.com/v3/autocomplete" #define URL_SEARCH "https://api.yelp.com/v3/businesses/search" #define LEFT_OFFSET 28 #define FONT_SIZE_LINEDIT 20 #define FONT_SIZE_LIST 18 #define TEXT_INPUT_WIDTH 800 #define SEARCH_BTN_SIZE 105 #define SPACER 15 #define WIDGET_WIDTH (SEARCH_BTN_SIZE + SPACER + TEXT_INPUT_WIDTH) #define DISPLAY_WIDTH TEXT_INPUT_WIDTH #define DISPLAY_HEIGHT 480 #define COMPLETE_W_WITH_KB 1080 #define COMPLETE_H_WITH_KB 1488 #define RESULT_ITEM_HEIGHT 80 #define MARGINS 25 #define AGL_REFRESH_DELAY 75 /* milliseconds */ #define SCROLLBAR_STYLE \ "QScrollBar:vertical {" \ " border: 2px solid grey;" \ " background: gray;" \ " width: 45px;" \ "}" using namespace std; MainApp::MainApp(Navigation *navigation):QMainWindow(Q_NULLPTR, Qt::FramelessWindowHint), networkManager(this),searchBtn(QIcon(tr(":/images/loupe-90.png")), tr(""), this), lineEdit(this),keyboard(QRect(0, 688, COMPLETE_W_WITH_KB, 720), this), mutex(QMutex::Recursive),token(""),currentSearchingText(""),currentSearchedText(""), pSearchReply(NULL),pInfoPanel(NULL),pResultList(NULL),currentLatitude(36.136261),currentLongitude(-115.151254), navicoreSession(0),currentIndex(0),fontId(-1),isInfoScreen(false), isInputDisplayed(false),isKeyboard(false),isAglNavi(false), naviapi(navigation) { //this->setAttribute(Qt::WA_TranslucentBackground); this->setStyleSheet("border: none;"); searchBtn.setStyleSheet("border: none; color: #FFFFFF;"); searchBtn.setMinimumSize(QSize(SEARCH_BTN_SIZE, SEARCH_BTN_SIZE)); searchBtn.setIconSize(searchBtn.size()); searchBtn.setGeometry(QRect(LEFT_OFFSET, 0, searchBtn.width(), searchBtn.height())); lineEdit.setStyleSheet("border: none; color: #FFFFFF;"); lineEdit.setMinimumSize(QSize(TEXT_INPUT_WIDTH, SEARCH_BTN_SIZE)); lineEdit.setPlaceholderText(QString(DEFAULT_TEXT)); font = lineEdit.font(); font.setPointSize(FONT_SIZE_LINEDIT); lineEdit.setFont(font); lineEdit.setTextMargins(MARGINS/2, 0, 0, 0); lineEdit.installEventFilter(this); lineEdit.setGeometry(QRect(LEFT_OFFSET + searchBtn.width() + SPACER, 0, lineEdit.width(), lineEdit.height())); lineEdit.setVisible(false); QFile file(NAVI_CONFIG_FILEPATH); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QByteArray data = file.readAll(); QJsonDocument jsonDoc(QJsonDocument::fromJson(data)); QJsonObject jsonObj(jsonDoc.object()); if (jsonObj.contains("latitude")) currentLatitude = jsonObj["latitude"].toDouble(); if (jsonObj.contains("longitude")) currentLongitude = jsonObj["longitude"].toDouble(); } /* We might need a Japanese font: */ QFile fontFile(":/fonts/DroidSansJapanese.ttf"); if (!fontFile.open(QIODevice::ReadOnly)) { TRACE_ERROR("failed to open font file"); } else { QByteArray fontData = fontFile.readAll(); fontId = QFontDatabase::addApplicationFontFromData(fontData); if (fontId < 0) { TRACE_ERROR("QFontDatabase::addApplicationFontFromData failed"); } } /* Check if "AGL_NAVI" env variable is set. If yes, we must notify * AGL environment when surface needs to be resized */ if (getenv("AGL_NAVI")) isAglNavi = true; connect(this, SIGNAL(positionGotSignal()), this, SLOT(positionGot())); this->setGeometry(QRect(this->pos().x(), this->pos().y(), COMPLETE_W_WITH_KB, COMPLETE_H_WITH_KB)); this->setStyleSheet("background-image: url(:/images/AGL_POI_Background.png);"); this->show(); } MainApp::~MainApp() { mutex.lock(); if (fontId >= 0) QFontDatabase::removeApplicationFont(fontId); searchBtn.disconnect(); lineEdit.disconnect(); networkManager.disconnect(); keyboard.disconnect(); delete pSearchReply; delete pInfoPanel; mutex.unlock(); } void MainApp::searchBtnClicked() { isInputDisplayed = !isInputDisplayed; TRACE_DEBUG("isInputDisplayed = %d", isInputDisplayed); DisplayLineEdit(isInputDisplayed); } void MainApp::DisplayLineEdit(bool display) { mutex.lock(); if (display) { lineEdit.setVisible(true); lineEdit.setFocus(); } else { if (pResultList) { pResultList->removeEventFilter(this); pResultList->setVisible(false); } if (pInfoPanel) { pInfoPanel->setVisible(false); } lineEdit.setText(tr("")); lineEdit.setVisible(false); } isInputDisplayed = display; mutex.unlock(); } void MainApp::UpdateAglSurfaces() { char cmd[1024]; TRACE_DEBUG("handle AGL demo surfaces (new surface is bigger)"); snprintf(cmd, 1023, "/usr/bin/LayerManagerControl set surface $SURFACE_ID_CLIENT source region 0 0 %d %d", this->width(), this->height()); TRACE_DEBUG("%s", cmd); system(cmd); snprintf(cmd, 1023, "/usr/bin/LayerManagerControl set surface $SURFACE_ID_CLIENT destination region $CLIENT_X $CLIENT_Y %d %d", this->width(), this->height()); TRACE_DEBUG("%s", cmd); system(cmd); } void MainApp::DisplayResultList(bool display) { mutex.lock(); if (display) { if (!pResultList) { pResultList = new QTreeWidget(this); pResultList->setStyleSheet("border: none; color: #FFFFFF;"); pResultList->setRootIsDecorated(false); pResultList->setEditTriggers(QTreeWidget::NoEditTriggers); pResultList->setSelectionBehavior(QTreeWidget::SelectRows); pResultList->setFrameStyle(QFrame::Box | QFrame::Plain); pResultList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); //pResultList->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); pResultList->setAttribute(Qt::WA_AcceptTouchEvents); pResultList->verticalScrollBar()->setStyleSheet(SCROLLBAR_STYLE); pResultList->header()->hide(); //font.setPointSize(FONT_SIZE_LIST); //pResultList->setFont(font); pResultList->installEventFilter(this); pResultList->setGeometry(QRect(LEFT_OFFSET + searchBtn.width() + SPACER, searchBtn.height() + SPACER, DISPLAY_WIDTH, DISPLAY_HEIGHT)); } pResultList->setVisible(true); pResultList->setFocus(); pResultList->update(); } else { if (pResultList) { pResultList->removeEventFilter(this); pResultList->setVisible(false); pResultList->update(); } lineEdit.setFocus(); } mutex.unlock(); } void MainApp::textChanged(const QString & text) { TRACE_INFO("New text is: %s", qPrintable(text)); /* do not handle text input if info panel is displayed: */ if (pInfoPanel && pInfoPanel->isVisible()) return; mutex.lock(); delete pSearchReply; /* cancel current search */ pSearchReply = NULL; if (text.length() == 0) /* if empty text -> no search */ { DisplayResultList(false); mutex.unlock(); return; } /* if text is the same as previous search -> no need to search again */ if (text == currentSearchedText) { DisplayResultList(true); FillResultList(Businesses, currentIndex); mutex.unlock(); return; } this->currentSearchingText = text; emit positionGotSignal(); mutex.unlock(); } void MainApp::textAdded(const QString & text) { mutex.lock(); lineEdit.setText(lineEdit.text() + text); // be sure any text is visible on initial input lineEdit.setVisible(true); mutex.unlock(); } void MainApp::keyPressed(int key) { mutex.lock(); if (key == '\b') /* backspace */ { int len = lineEdit.text().length(); if (len > 0) lineEdit.setText(lineEdit.text().remove(len-1, 1)); } mutex.unlock(); } void MainApp::itemClicked() { mutex.lock(); if (isInfoScreen) { DisplayInformation(true); } else { SetDestination(); DisplayLineEdit(false); } mutex.unlock(); } void MainApp::ParseJsonBusinessList(const char* buf, std::vector & Output) { json_object *jobj = json_tokener_parse(buf); if (!jobj) { TRACE_ERROR("json_tokener_parse failed"); cerr << "json_tokener_parse failed: " << buf << endl; return; } json_object_object_foreach(jobj, key, val) { (void)key; json_object *value; if (json_object_get_type(val) == json_type_array) { TRACE_DEBUG_JSON("an array was found"); if(json_object_object_get_ex(jobj, "businesses", &value)) { TRACE_DEBUG_JSON("an business was found"); int arraylen = json_object_array_length(value); for (int i = 0; i < arraylen; i++) { Business NewBusiness; json_object* medi_array_obj, *medi_array_obj_elem; medi_array_obj = json_object_array_get_idx(value, i); if (medi_array_obj) { if (json_object_object_get_ex(medi_array_obj, "rating", &medi_array_obj_elem)) { NewBusiness.Rating = json_object_get_double(medi_array_obj_elem); TRACE_DEBUG_JSON("got Rating : %f", NewBusiness.Rating); } if (json_object_object_get_ex(medi_array_obj, "distance", &medi_array_obj_elem)) { NewBusiness.Distance = json_object_get_double(medi_array_obj_elem); TRACE_DEBUG_JSON("got Distance : %f", NewBusiness.Distance); } if (json_object_object_get_ex(medi_array_obj, "review_count", &medi_array_obj_elem)) { NewBusiness.ReviewCount = json_object_get_int(medi_array_obj_elem); TRACE_DEBUG_JSON("got ReviewCount : %u", NewBusiness.ReviewCount); } if (json_object_object_get_ex(medi_array_obj, "name", &medi_array_obj_elem)) { NewBusiness.Name = QString(json_object_get_string(medi_array_obj_elem)); TRACE_DEBUG_JSON("got Name : %s", qPrintable(NewBusiness.Name)); } if (json_object_object_get_ex(medi_array_obj, "image_url", &medi_array_obj_elem)) { NewBusiness.ImageUrl = QString(json_object_get_string(medi_array_obj_elem)); TRACE_DEBUG_JSON("got ImageUrl : %s", qPrintable(NewBusiness.ImageUrl)); } if (json_object_object_get_ex(medi_array_obj, "phone", &medi_array_obj_elem)) { NewBusiness.Phone = QString(json_object_get_string(medi_array_obj_elem)); TRACE_DEBUG_JSON("got Phone : %s", qPrintable(NewBusiness.Phone)); } if (json_object_object_get_ex(medi_array_obj, "coordinates", &medi_array_obj_elem)) { json_object *value2; TRACE_DEBUG_JSON("coordinates were found"); if(json_object_object_get_ex(medi_array_obj_elem, "latitude", &value2)) { NewBusiness.Latitude = json_object_get_double(value2); TRACE_DEBUG_JSON("got Latitude : %f", NewBusiness.Latitude); } if(json_object_object_get_ex(medi_array_obj_elem, "longitude", &value2)) { NewBusiness.Longitude = json_object_get_double(value2); TRACE_DEBUG_JSON("got Longitude : %f", NewBusiness.Longitude); } } if (json_object_object_get_ex(medi_array_obj, "location", &medi_array_obj_elem)) { json_object *value2; TRACE_DEBUG_JSON("a location was found"); /* TODO: how do we deal with address2 and address3 ? */ if(json_object_object_get_ex(medi_array_obj_elem, "address1", &value2)) { NewBusiness.Address = QString(json_object_get_string(value2)); TRACE_DEBUG_JSON("got Address : %s", qPrintable(NewBusiness.Address)); } if(json_object_object_get_ex(medi_array_obj_elem, "city", &value2)) { NewBusiness.City = QString(json_object_get_string(value2)); TRACE_DEBUG_JSON("got City : %s", qPrintable(NewBusiness.City)); } if(json_object_object_get_ex(medi_array_obj_elem, "state", &value2)) { NewBusiness.State = QString(json_object_get_string(value2)); TRACE_DEBUG_JSON("got State : %s", qPrintable(NewBusiness.State)); } if(json_object_object_get_ex(medi_array_obj_elem, "zip_code", &value2)) { NewBusiness.ZipCode = QString(json_object_get_string(value2)); TRACE_DEBUG_JSON("got ZipCode : %s", qPrintable(NewBusiness.ZipCode)); } if(json_object_object_get_ex(medi_array_obj_elem, "country", &value2)) { NewBusiness.Country = QString(json_object_get_string(value2)); TRACE_DEBUG_JSON("got Country : %s", qPrintable(NewBusiness.Country)); } } /* TODO: parse categories */ /* Add business in our list: */ Businesses.push_back(NewBusiness); } } } } } json_object_put(jobj); } bool MainApp::eventFilter(QObject *obj, QEvent *ev) { bool ret = false; mutex.lock(); if (obj == pResultList) { //TRACE_DEBUG("ev->type() = %d", (int)ev->type()); if (ev->type() == QEvent::KeyPress) { bool consumed = false; int key = static_cast(ev)->key(); TRACE_DEBUG("key pressed (%d)", key); switch (key) { case Qt::Key_Enter: case Qt::Key_Return: TRACE_DEBUG("enter or return"); if (isInfoScreen) { DisplayInformation(true); } else { SetDestination(); DisplayLineEdit(false); } consumed = true; break; case Qt::Key_Escape: TRACE_DEBUG("escape"); DisplayResultList(false); consumed = true; break; case Qt::Key_Up: case Qt::Key_Down: case Qt::Key_Home: case Qt::Key_End: case Qt::Key_PageUp: case Qt::Key_PageDown: TRACE_DEBUG("arrows"); break; default: TRACE_DEBUG("default"); lineEdit.event(ev); break; } mutex.unlock(); return consumed; } } else if (obj == &lineEdit) { if (pInfoPanel && ev->type() == QEvent::KeyPress) { switch(static_cast(ev)->key()) { case Qt::Key_Escape: TRACE_DEBUG("Escape !"); DisplayInformation(false); DisplayResultList(true); FillResultList(Businesses, currentIndex); break; case Qt::Key_Enter: case Qt::Key_Return: TRACE_DEBUG("Go !"); SetDestination(currentIndex); DisplayLineEdit(false); break; default: break; } } } else { ret = QMainWindow::eventFilter(obj, ev); } mutex.unlock(); return ret; } void MainApp::resizeEvent(QResizeEvent* event) { QMainWindow::resizeEvent(event); if (isAglNavi) { QTimer::singleShot(AGL_REFRESH_DELAY, Qt::CoarseTimer, this, SLOT(UpdateAglSurfaces())); } } void MainApp::SetDestination(int index) { mutex.lock(); /* if pResultList exists, take the selected index * otherwise, take the index given as parameter */ if (pResultList) { QList SelectedItems = pResultList->selectedItems(); if (SelectedItems.size() > 0) { /* select the first selected item : */ index = pResultList->indexOfTopLevelItem(*SelectedItems.begin()); } } TRACE_DEBUG("index is: %d", index); /* retrieve the coordinates of this item : */ this->destinationLatitude = Businesses[index].Latitude; this->destinationLongitude = Businesses[index].Longitude; SetWayPoints(0); mutex.unlock(); if (navWinRaiseCb) { // Attempt to let any outstanding repaints finish by flushing // and then waiting slightly before raising the nav window. // It's currently unclear why repaints can be missed if this // is not done. qApp->processEvents(); //TRACE_DEBUG("Calling nav window raise callback"); QTimer::singleShot(100, this, SLOT(callNavWinRaiseCb())); } } void MainApp::DisplayInformation(bool display) { mutex.lock(); if (display) { /* pResultList must exist, so that we can retrieve the selected index: */ if (!pResultList) { TRACE_ERROR("pResultList is null"); mutex.unlock(); return; } QList SelectedItems = pResultList->selectedItems(); if (SelectedItems.size() <= 0) { TRACE_ERROR("no item is selected"); mutex.unlock(); return; } /* select the first selected item : */ currentIndex = pResultList->indexOfTopLevelItem(*SelectedItems.begin()); /* Hide results */ DisplayResultList(false); /* Display info for the selected item: */ if (!pInfoPanel) { QRect rect(LEFT_OFFSET + searchBtn.width() + SPACER, searchBtn.height(), DISPLAY_WIDTH, DISPLAY_HEIGHT); pInfoPanel = new InfoPanel(this, rect); } pInfoPanel->populateInfo(Businesses[currentIndex]); pInfoPanel->setVisible(true); pInfoPanel->update(); connect(pInfoPanel->getGoButton(), SIGNAL(clicked(bool)), this, SLOT(goClicked())); connect(pInfoPanel->getCancelButton(), SIGNAL(clicked(bool)), this, SLOT(cancelClicked())); } else { if (pInfoPanel) { pInfoPanel->setVisible(false); pInfoPanel->getGoButton()->disconnect(); pInfoPanel->getCancelButton()->disconnect(); pInfoPanel->update(); } lineEdit.setFocus(); } mutex.unlock(); } void MainApp::networkReplySearch(QNetworkReply* reply) { QByteArray buf; mutex.lock(); /* memorize the text which gave this result: */ currentSearchedText = lineEdit.text(); if (reply->error() == QNetworkReply::NoError) { // we only handle this callback if it matches the last search request: if (reply != pSearchReply) { TRACE_INFO("this reply is already too late (or about a different network request)"); mutex.unlock(); return; } buf = reply->readAll(); if (buf.isEmpty()) { mutex.unlock(); return; } currentIndex = 0; Businesses.clear(); ParseJsonBusinessList(buf.data(), Businesses); DisplayResultList(true); FillResultList(Businesses); } else { fprintf(stderr,"POI: reply error network please check to poikey and system time (adjusted?)\n"); } mutex.unlock(); } /* pResultList must be allocated at this point ! */ int MainApp::FillResultList(vector & list, int focusIndex) { int nbElem = 0; mutex.lock(); pResultList->setUpdatesEnabled(false); pResultList->clear(); /* filling the dropdown menu: */ for (vector::iterator it = list.begin(); it != list.end(); it++) { /* workaround to avoid entries with wrong coordinates returned by Yelp: */ if (IsCoordinatesConsistent(*it) == false) { list.erase(it--); continue; } QTreeWidgetItem * item = new QTreeWidgetItem(pResultList); ClickableLabel *label = new ClickableLabel(""+(*it).Name+ "
"+(*it).Address+", "+(*it).City+", "+(*it).State+ " "+(*it).ZipCode+", "+(*it).Country, pResultList); label->setTextFormat(Qt::RichText); font.setPointSize(FONT_SIZE_LIST); label->setFont(font); label->setIndent(MARGINS); label->setAttribute(Qt::WA_AcceptTouchEvents); item->setSizeHint(0, QSize(TEXT_INPUT_WIDTH, RESULT_ITEM_HEIGHT)); pResultList->setItemWidget(item, 0, label); connect(label, SIGNAL(clicked()), this, SLOT(itemClicked())); //item->setText(0, (*it).Name); if (nbElem == focusIndex) { pResultList->setCurrentItem(item); } nbElem++; } pResultList->setUpdatesEnabled(true); mutex.unlock(); return nbElem; } /* Well... some of the POI returned by Yelp have coordinates which are * completely inconsistent with the distance at which the POI is * supposed to be. * https://github.com/Yelp/yelp-fusion/issues/104 * Let's skip them for the moment: */ #define PI 3.14159265 #define EARTH_RADIUS 6371000 static inline double toRadians(double a) { return a * PI / 180.0; } bool MainApp::IsCoordinatesConsistent(Business & business) { double lat1 = toRadians(currentLatitude); double lon1 = toRadians(currentLongitude); double lat2 = toRadians(business.Latitude); double lon2 = toRadians(business.Longitude); double x = (lon2 - lon1) * cos((lat1 + lat2)/2); double y = lat2 - lat1; double DistanceFromCoords = EARTH_RADIUS * sqrt(pow(x, 2) + pow(y, 2)); /* if calculated distance is not between +/- 10% of the announced * distance -> skip this POI: */ if (DistanceFromCoords < business.Distance * 0.9 || DistanceFromCoords > business.Distance * 1.1) { TRACE_ERROR("Announced distance: %f, calculated distance: %f", business.Distance, DistanceFromCoords); return false; } return true; } /* end of workaround */ int MainApp::AuthenticatePOI(const QString & CredentialsFile) { char buf[512]; QString AppId; QString AppSecret; QString ProxyHostName; QString PortStr; QString User; QString Password; int portnum; /* First, read AppId and AppSecret from credentials file: */ FILE* filep = fopen(qPrintable(CredentialsFile), "r"); if (!filep) { fprintf(stderr,"Failed to open credentials file \"%s\": %m", qPrintable(CredentialsFile)); return -1; } if (!fgets(buf, 512, filep)) { fprintf(stderr,"Failed to read AppId from credentials file \"%s\"", qPrintable(CredentialsFile)); fclose(filep); return -1; } if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; AppId = QString(buf); if (!fgets(buf, 512, filep)) { fprintf(stderr,"Failed to read AppSecret from credentials file \"%s\"", qPrintable(CredentialsFile)); fclose(filep); return -1; } if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; AppSecret = QString(buf); QNetworkProxy proxy; //ProxyHostName if (!fgets(buf, 512, filep)) { TRACE_INFO("Failed to read ProxyHostName from credentials file \"%s\"", qPrintable(CredentialsFile)); } else { if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; ProxyHostName = QString(buf); ProxyHostName.replace(0, 14, tr("")); //Port if (!fgets(buf, 512, filep)) { TRACE_ERROR("Failed to read Port from credentials file \"%s\"", qPrintable(CredentialsFile)); fclose(filep); return -1; } if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; PortStr = QString(buf); PortStr.replace(0, 5, tr("")); portnum = PortStr.toInt(); //User if (!fgets(buf, 512, filep)) { TRACE_ERROR("Failed to read User from credentials file \"%s\"", qPrintable(CredentialsFile)); fclose(filep); return -1; } if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; User = QString(buf); User.replace(0, 5, tr("")); //Password if (!fgets(buf, 512, filep)) { TRACE_ERROR("Failed to read Password from credentials file \"%s\"", qPrintable(CredentialsFile)); fclose(filep); return -1; } if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; Password = QString(buf); Password.replace(0, 9, tr("")); proxy.setType(QNetworkProxy::HttpProxy); proxy.setHostName(qPrintable(ProxyHostName)); proxy.setPort(portnum); proxy.setUser(qPrintable(User)); proxy.setPassword(qPrintable(Password)); QNetworkProxy::setApplicationProxy(proxy); } fclose(filep); TRACE_INFO("Found credentials"); /* Then, send a HTTP request to get the token and wait for answer (synchronously): */ token = AppSecret; return 0; } int MainApp::StartMonitoringUserInput() { connect(&searchBtn, SIGNAL(clicked(bool)), this, SLOT(searchBtnClicked())); connect(&lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &))); connect(&networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkReplySearch(QNetworkReply*))); connect(&keyboard, SIGNAL(keyClicked(const QString &)), this, SLOT(textAdded(const QString &))); connect(&keyboard, SIGNAL(specialKeyClicked(int)), this, SLOT(keyPressed(int))); return 1; } void MainApp::SetWayPoints(uint32_t myRoute) { /* set the destination : */ naviapi->broadcastStatus("stop"); naviapi->sendWaypoint(this->destinationLatitude, this->destinationLongitude); } void MainApp::goClicked() { TRACE_DEBUG("Go clicked !"); DisplayInformation(false); DisplayResultList(true); SetDestination(currentIndex); } void MainApp::cancelClicked() { TRACE_DEBUG("Cancel clicked !"); DisplayInformation(false); DisplayResultList(true); } void MainApp::getAllSessions_reply(const std::map< uint32_t, std::string >& allSessions) { mutex.lock(); if (allSessions.empty()) { TRACE_ERROR("Error: could not find an instance of Navicore"); mutex.unlock(); return; } this->navicoreSession = allSessions.begin()->first; TRACE_INFO("Current session: %d", this->navicoreSession); mutex.unlock(); } void MainApp::positionGot() { mutex.lock(); /* let's generate a search request : */ QString myUrlStr = URL_SEARCH + tr("?") + tr("term=") + currentSearchingText + tr("&latitude=") + QString::number(currentLatitude) + tr("&longitude=") + QString::number(currentLongitude); TRACE_DEBUG("URL: %s", qPrintable(myUrlStr)); QUrl myUrl = QUrl(myUrlStr); QNetworkRequest req(myUrl); req.setRawHeader(QByteArray("Authorization"), (tr("bearer ") + token).toLocal8Bit()); /* Then, send a HTTP request to get the token and wait for answer (synchronously): */ pSearchReply = networkManager.get(req); mutex.unlock(); }