#include "qt/search_panel.hpp" #include "qt/draw_widget.hpp" #include "map/bookmark_manager.hpp" #include "map/user_mark_container.hpp" #include "drape/constants.hpp" #include "platform/measurement_utils.hpp" #include "std/bind.hpp" #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #include #include #include #include #include #include #include #else #include #include #include #include #include #include #include #endif namespace qt { SearchPanel::SearchPanel(DrawWidget * drawWidget, QWidget * parent) : QWidget(parent), m_pDrawWidget(drawWidget), m_busyIcon(":/ui/busy.png") { m_pEditor = new QLineEdit(this); connect(m_pEditor, SIGNAL(textChanged(QString const &)), this, SLOT(OnSearchTextChanged(QString const &))); m_pTable = new QTableWidget(0, 4 /*columns*/, this); m_pTable->setFocusPolicy(Qt::NoFocus); m_pTable->setAlternatingRowColors(true); m_pTable->setShowGrid(false); m_pTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pTable->verticalHeader()->setVisible(false); m_pTable->horizontalHeader()->setVisible(false); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) m_pTable->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); #else m_pTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); #endif connect(m_pTable, SIGNAL(cellClicked(int, int)), this, SLOT(OnSearchPanelItemClicked(int,int))); m_pClearButton = new QPushButton(this); connect(m_pClearButton, SIGNAL(pressed()), this, SLOT(OnClearButton())); m_pClearButton->setVisible(false); m_pClearButton->setFocusPolicy(Qt::NoFocus); m_pAnimationTimer = new QTimer(this); connect(m_pAnimationTimer, SIGNAL(timeout()), this, SLOT(OnAnimationTimer())); QHBoxLayout * horizontalLayout = new QHBoxLayout(); horizontalLayout->addWidget(m_pEditor); horizontalLayout->addWidget(m_pClearButton); QVBoxLayout * verticalLayout = new QVBoxLayout(); verticalLayout->addLayout(horizontalLayout); verticalLayout->addWidget(m_pTable); setLayout(verticalLayout); // for multithreading support CHECK(connect(this, SIGNAL(SearchResultSignal(ResultsT *)), this, SLOT(OnSearchResult(ResultsT *)), Qt::QueuedConnection), ()); m_params.m_onResults = bind(&SearchPanel::SearchResultThreadFunc, this, _1); } void SearchPanel::SearchResultThreadFunc(ResultsT const & result) { emit SearchResultSignal(new ResultsT(result)); } namespace { QTableWidgetItem * CreateItem(QString const & s) { QTableWidgetItem * item = new QTableWidgetItem(s); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); return item; } } // namespace void SearchPanel::ClearResults() { m_pTable->clear(); m_pTable->setRowCount(0); m_results.clear(); } void SearchPanel::OnSearchResult(ResultsT * results) { unique_ptr const guard(results); if (results->IsEndMarker()) { if (results->IsEndedNormal()) { // stop search busy indicator m_pAnimationTimer->stop(); m_pClearButton->setIcon(QIcon(":/ui/x.png")); } } else { ClearResults(); for (auto const & res : *results) { QString const name = QString::fromStdString(res.GetString()); QString strHigh; int pos = 0; for (size_t r = 0; r < res.GetHighlightRangesCount(); ++r) { pair const & range = res.GetHighlightRange(r); strHigh.append(name.mid(pos, range.first - pos)); strHigh.append(""); strHigh.append(name.mid(range.first, range.second)); strHigh.append(""); pos = range.first + range.second; } strHigh.append(name.mid(pos)); int const rowCount = m_pTable->rowCount(); m_pTable->insertRow(rowCount); m_pTable->setCellWidget(rowCount, 1, new QLabel(strHigh)); m_pTable->setItem(rowCount, 2, CreateItem(QString::fromStdString(res.GetAddress()))); if (res.GetResultType() == ResultT::RESULT_FEATURE) { m_pTable->setItem(rowCount, 0, CreateItem(QString::fromStdString(res.GetFeatureType()))); m_pTable->setItem(rowCount, 3, CreateItem(m_pDrawWidget->GetDistance(res).c_str())); } m_results.push_back(res); } } } // TODO: This code only for demonstration purposes and will be removed soon bool SearchPanel::TryChangeMapStyleCmd(QString const & str) { // Hook for shell command on change map style bool const isDark = (str == "mapstyle:dark") || (str == "?dark"); bool const isLight = isDark ? false : (str == "mapstyle:light") || (str == "?light"); bool const isOld = isDark || isLight ? false : (str == "?oldstyle"); if (!isDark && !isLight && !isOld) return false; // close Search panel m_pEditor->setText(""); parentWidget()->hide(); // change color scheme for the Map activity MapStyle const mapStyle = isOld ? MapStyleLight : (isDark ? MapStyleDark : MapStyleClear); m_pDrawWidget->SetMapStyle(mapStyle); return true; } // TODO: This code only for demonstration purposes and will be removed soon bool SearchPanel::TryChangeRouterCmd(QString const & str) { routing::RouterType routerType; if (str == "?pedestrian") routerType = routing::RouterType::Pedestrian; else if (str == "?vehicle") routerType = routing::RouterType::Vehicle; else if (str == "?bicycle") routerType = routing::RouterType::Bicycle; else return false; m_pEditor->setText(""); parentWidget()->hide(); m_pDrawWidget->SetRouter(routerType); return true; } // TODO: This code only for demonstration purposes and will be removed soon bool SearchPanel::Try3dModeCmd(QString const & str) { bool const is3dModeOn = (str == "?3d"); bool const is3dBuildingsOn = (str == "?b3d"); bool const is3dModeOff = (str == "?2d"); if (!is3dModeOn && !is3dBuildingsOn && !is3dModeOff) return false; m_pDrawWidget->GetFramework().Save3dMode(is3dModeOn || is3dBuildingsOn, is3dBuildingsOn); m_pDrawWidget->GetFramework().Allow3dMode(is3dModeOn || is3dBuildingsOn, is3dBuildingsOn); return true; } bool SearchPanel::TryMigrate(QString const & str) { bool const isMigrate = (str == "?migrate"); if (!isMigrate) return false; m_pEditor->setText(""); parentWidget()->hide(); auto const stateChanged = [&](storage::TCountryId const & id) { storage::Status const nextStatus = m_pDrawWidget->GetFramework().GetStorage().GetPrefetchStorage()->CountryStatusEx(id); LOG_SHORT(LINFO, (id, "status :", nextStatus)); if (nextStatus == storage::Status::EOnDisk) { LOG_SHORT(LINFO, ("Prefetch done. Ready to migrate.")); m_pDrawWidget->GetFramework().Migrate(); } }; auto const progressChanged = [](storage::TCountryId const & id, storage::MapFilesDownloader::TProgress const & sz) { LOG(LINFO, (id, "downloading progress:", sz)); }; ms::LatLon curPos(55.7, 37.7); m_pDrawWidget->GetFramework().PreMigrate(curPos, stateChanged, progressChanged); return true; } bool SearchPanel::TryDisplacementModeCmd(QString const & str) { bool const isDefaultDisplacementMode = (str == "?dm:default"); bool const isHotelDisplacementMode = (str == "?dm:hotel"); if (!isDefaultDisplacementMode && !isHotelDisplacementMode) return false; if (isDefaultDisplacementMode) { m_pDrawWidget->GetFramework().SetDisplacementMode(DisplacementModeManager::SLOT_DEBUG, false /* show */); } else if (isHotelDisplacementMode) { m_pDrawWidget->GetFramework().SetDisplacementMode(DisplacementModeManager::SLOT_DEBUG, true /* show */); } return true; } void SearchPanel::OnSearchTextChanged(QString const & str) { QString const normalized = str.normalized(QString::NormalizationForm_KC); // TODO: This code only for demonstration purposes and will be removed soon if (TryChangeMapStyleCmd(normalized)) return; if (TryChangeRouterCmd(normalized)) return; if (Try3dModeCmd(normalized)) return; if (TryMigrate(normalized)) return; if (TryDisplacementModeCmd(normalized)) return; // search even with empty query if (!normalized.isEmpty()) { m_params.m_query = normalized.toUtf8().constData(); if (m_pDrawWidget->Search(m_params)) { // show busy indicator if (!m_pAnimationTimer->isActive()) m_pAnimationTimer->start(200); m_pClearButton->setFlat(true); m_pClearButton->setVisible(true); } } else { ClearResults(); m_pDrawWidget->GetFramework().CancelSearch(search::Mode::Everywhere); // hide X button m_pClearButton->setVisible(false); } } void SearchPanel::OnSearchPanelItemClicked(int row, int) { ASSERT_EQUAL(m_results.size(), static_cast(m_pTable->rowCount()), ()); if (m_results[row].IsSuggest()) { // insert suggestion into the search bar string const suggestion = m_results[row].GetSuggestionString(); m_pEditor->setText(QString::fromUtf8(suggestion.c_str())); } else { // center viewport on clicked item m_pDrawWidget->ShowSearchResult(m_results[row]); } } void SearchPanel::hideEvent(QHideEvent *) { m_pDrawWidget->GetFramework().CancelSearch(search::Mode::Everywhere); } void SearchPanel::OnAnimationTimer() { static int angle = 0; QMatrix rm; angle += 15; if (angle >= 360) angle = 0; rm.rotate(angle); m_pClearButton->setIcon(QIcon(m_busyIcon.transformed(rm))); } void SearchPanel::OnClearButton() { m_pEditor->setText(""); } } // namespace qt