[qt][search] Added view for search results.

This commit is contained in:
Yuri Gorshenin 2017-03-15 15:56:53 +03:00
parent bd250b5deb
commit 2b46148fab
17 changed files with 398 additions and 67 deletions

View file

@ -1089,9 +1089,10 @@ void Framework::SetVisibleViewport(m2::RectD const & rect)
m_drapeEngine->SetVisibleViewport(rect);
}
void Framework::ShowRect(m2::RectD const & rect, int maxScale)
void Framework::ShowRect(m2::RectD const & rect, int maxScale, bool animation)
{
CallDrapeFunction(bind(&df::DrapeEngine::SetModelViewRect, _1, rect, true, maxScale, true));
CallDrapeFunction(bind(&df::DrapeEngine::SetModelViewRect, _1, rect, true /* applyRotation */,
maxScale /* zoom */, animation));
}
void Framework::ShowRect(m2::AnyRectD const & rect)

View file

@ -275,6 +275,9 @@ public:
Index const & GetIndex() const { return m_model.GetIndex(); }
search::Engine & GetSearchEngine() { return *m_searchEngine; }
search::Engine const & GetSearchEngine() const { return *m_searchEngine; }
/// @name Bookmarks, Tracks and other UserMarks
//@{
/// Scans and loads all kml files with bookmarks in WritableDir.
@ -571,7 +574,7 @@ public:
void SetVisibleViewport(m2::RectD const & rect);
/// - Check minimal visible scale according to downloaded countries.
void ShowRect(m2::RectD const & rect, int maxScale = -1);
void ShowRect(m2::RectD const & rect, int maxScale = -1, bool animation = true);
void ShowRect(m2::AnyRectD const & rect);
void GetTouchRect(m2::PointD const & center, uint32_t pxRadius, m2::AnyRectD & rect);

View file

@ -8,13 +8,21 @@ include_directories(${OMIM_ROOT}/3party/glm)
set(
SRC
assessment_tool.cc
assessment_tool.cpp
helpers.cpp
helpers.hpp
languages_list.cpp
languages_list.hpp
main_model.cpp
main_model.hpp
main_model.hpp
main_view.cpp
main_view.hpp
model.hpp
sample_view.cpp
sample_view.hpp
samples_view.cpp
samples_view.hpp
view.hpp
)

View file

@ -14,10 +14,6 @@
DEFINE_string(resources_path, "", "Path to resources directory");
DEFINE_string(data_path, "", "Path to data directory");
namespace
{
} // namespace
int main(int argc, char ** argv)
{
search::ChangeMaxNumberOfOpenFiles(search::kMaxOpenFiles);
@ -36,7 +32,7 @@ int main(int argc, char ** argv)
Framework framework;
MainView view(framework);
MainModel model;
MainModel model(framework);
model.SetView(view);
view.SetModel(model);

View file

@ -0,0 +1,13 @@
#include "search/search_quality/assessment_tool/helpers.hpp"
#include "base/string_utils.hpp"
QString ToQString(strings::UniString const & s)
{
return QString::fromUtf8(strings::ToUtf8(s).c_str());
}
QString ToQString(std::string const & s)
{
return QString::fromUtf8(s.c_str());
}

View file

@ -0,0 +1,22 @@
#pragma once
#include <string>
#include <utility>
#include <QtCore/QString>
namespace strings
{
class UniString;
}
QString ToQString(strings::UniString const & s);
QString ToQString(std::string const & s);
template <typename Layout, typename... Args>
Layout * BuildLayoutWithoutMargins(Args &&... args)
{
auto * layout = new Layout(std::forward<Args>(args)...);
layout->setContentsMargins(0 /* left */, 0 /* top */, 0 /* right */, 0 /* bottom */);
return layout;
}

View file

@ -0,0 +1,21 @@
#include "search/search_quality/assessment_tool/languages_list.hpp"
#include "search/search_quality/assessment_tool/helpers.hpp"
#include "coding/multilang_utf8_string.hpp"
LanguagesList::LanguagesList(QWidget * parent) : QComboBox(parent)
{
auto langs = StringUtf8Multilang::GetSupportedLanguages();
for (auto const & lang : langs)
addItem(ToQString(lang.m_code));
}
void LanguagesList::Select(string const & lang)
{
auto const index = StringUtf8Multilang::GetLangIndex(lang);
if (index != StringUtf8Multilang::kUnsupportedLanguageCode)
setCurrentIndex(index);
else
setCurrentIndex(StringUtf8Multilang::kDefaultCode);
}

View file

@ -0,0 +1,15 @@
#pragma once
#include <string>
#include <QtWidgets/QComboBox>
class QWidget;
class LanguagesList : public QComboBox
{
public:
explicit LanguagesList(QWidget * parent);
void Select(std::string const & lang);
};

View file

@ -1,7 +1,16 @@
#include "search/search_quality/assessment_tool/main_model.hpp"
#include "search/search_params.hpp"
#include "search/search_quality/assessment_tool/view.hpp"
#include "map/framework.hpp"
#include "geometry/mercator.hpp"
#include "coding/multilang_utf8_string.hpp"
#include "platform/platform.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
@ -9,6 +18,8 @@
#include <fstream>
#include <iterator>
MainModel::MainModel(Framework & framework) : m_framework(framework) {}
void MainModel::Open(std::string const & path)
{
CHECK(m_view, ());
@ -38,5 +49,37 @@ void MainModel::OnSampleSelected(int index)
CHECK_GREATER_OR_EQUAL(index, 0, ());
CHECK_LESS(index, m_samples.size(), ());
CHECK(m_view, ());
auto const & sample = m_samples[index];
m_view->ShowSample(m_samples[index]);
auto & engine = m_framework.GetSearchEngine();
{
auto latLon = MercatorBounds::ToLatLon(sample.m_pos);
search::SearchParams params;
params.m_query = strings::ToUtf8(sample.m_query);
params.m_inputLocale = sample.m_locale;
params.m_suggestsEnabled = false;
params.SetPosition(latLon.lat, latLon.lon);
auto const timestamp = ++m_queryTimestamp;
m_lastShownResult = 0;
params.m_onResults = [this, timestamp](search::Results const & results) {
GetPlatform().RunOnGuiThread([this, timestamp, results]() { OnResults(timestamp, results); });
};
if (auto handle = m_queryHandle.lock())
handle->Cancel();
m_queryHandle = engine.Search(params, sample.m_viewport);
}
}
void MainModel::OnResults(uint64_t timestamp, search::Results const & results)
{
if (timestamp != m_queryTimestamp)
return;
m_view->ShowResults(results.begin() + m_lastShownResult, results.end());
m_lastShownResult = results.GetCount();
}

View file

@ -1,19 +1,36 @@
#pragma once
#include "search/engine.hpp"
#include "search/search_quality/assessment_tool/model.hpp"
#include "search/search_quality/sample.hpp"
#include <cstdint>
#include <vector>
#include <memory>
class Framework;
namespace search
{
class Results;
}
class MainModel : public Model
{
public:
MainModel(Framework & framework);
// Model overrides:
void Open(std::string const & path) override;
void OnSampleSelected(int index) override;
private:
void OnResults(uint64_t timestamp, search::Results const & results);
Framework & m_framework;
std::vector<search::Sample> m_samples;
std::weak_ptr<search::ProcessorHandle> m_queryHandle;
uint64_t m_queryTimestamp = 0;
size_t m_lastShownResult = 0;
};

View file

@ -1,6 +1,9 @@
#include "search/search_quality/assessment_tool/main_view.hpp"
#include "search/search_quality/assessment_tool/main_model.hpp"
#include "search/search_quality/assessment_tool/helpers.hpp"
#include "search/search_quality/assessment_tool/model.hpp"
#include "search/search_quality/assessment_tool/sample_view.hpp"
#include "search/search_quality/assessment_tool/samples_view.hpp"
#include "qt/qt_common/map_widget.hpp"
#include "qt/qt_common/scale_slider.hpp"
@ -8,14 +11,12 @@
#include "map/framework.hpp"
#include "base/assert.hpp"
#include "base/stl_add.hpp"
#include "base/string_utils.hpp"
#include <QtCore/QList>
#include <QtCore/Qt>
#include <QtWidgets/QDockWidget>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QToolBar>
@ -39,17 +40,20 @@ MainView::~MainView()
void MainView::SetSamples(std::vector<search::Sample> const & samples)
{
m_samplesModel->removeRows(0, m_samplesModel->rowCount());
for (auto const & sample : samples)
{
m_samplesModel->appendRow(
new QStandardItem(QString::fromUtf8(strings::ToUtf8(sample.m_query).c_str())));
}
m_samplesView->SetSamples(samples);
}
void MainView::ShowSample(search::Sample const & sample)
{
// TODO (@y): implement a dock view for search sample.
m_framework.ShowRect(sample.m_viewport, -1 /* maxScale */, false /* animation */);
m_sampleView->SetContents(sample);
m_sampleView->show();
}
void MainView::ShowResults(search::Results::Iter begin, search::Results::Iter end)
{
m_sampleView->ShowResults(begin, end);
}
void MainView::ShowError(std::string const & msg)
@ -70,84 +74,77 @@ void MainView::OnSampleSelected(QItemSelection const & current)
void MainView::InitMenuBar()
{
CHECK(m_samplesDock.get(), ());
auto * bar = menuBar();
auto * fileMenu = bar->addMenu(tr("&File"));
{
auto open = make_unique<QAction>(tr("&Open queries..."), this);
auto * open = new QAction(tr("&Open queries..."), this /* parent */);
open->setShortcuts(QKeySequence::Open);
open->setStatusTip(tr("Open the file with queries for assessment"));
connect(open.get(), &QAction::triggered, this, &MainView::Open);
fileMenu->addAction(open.release());
connect(open, &QAction::triggered, this, &MainView::Open);
fileMenu->addAction(open);
}
fileMenu->addSeparator();
{
auto quit = make_unique<QAction>(tr("&Quit"), this);
auto * quit = new QAction(tr("&Quit"), this /* parent */);
quit->setShortcuts(QKeySequence::Quit);
quit->setStatusTip(tr("Exit the tool"));
connect(quit.get(), &QAction::triggered, this, &QWidget::close);
fileMenu->addAction(quit.release());
connect(quit, &QAction::triggered, this, &QWidget::close);
fileMenu->addAction(quit);
}
auto * viewMenu = bar->addMenu(tr("&View"));
{
CHECK(m_samplesDock != nullptr, ());
viewMenu->addAction(m_samplesDock->toggleViewAction());
}
{
CHECK(m_sampleDock != nullptr, ());
viewMenu->addAction(m_sampleDock->toggleViewAction());
}
}
void MainView::InitMapWidget()
{
auto widget = make_unique<QWidget>(this /* parent */);
auto * widget = new QWidget(this /* parent */);
auto * layout = BuildLayoutWithoutMargins<QHBoxLayout>(widget /* parent */);
widget->setLayout(layout);
auto layout = make_unique<QHBoxLayout>(widget.get() /* parent */);
layout->setContentsMargins(0 /* left */, 0 /* top */, 0 /* right */, 0 /* bottom */);
{
auto mapWidget = make_unique<qt::common::MapWidget>(m_framework, widget.get() /* parent */);
auto toolBar = make_unique<QToolBar>(widget.get() /* parent */);
auto * mapWidget = new qt::common::MapWidget(m_framework, widget /* parent */);
auto * toolBar = new QToolBar(widget /* parent */);
toolBar->setOrientation(Qt::Vertical);
toolBar->setIconSize(QSize(32, 32));
qt::common::ScaleSlider::Embed(Qt::Vertical, *toolBar, *mapWidget);
layout->addWidget(mapWidget.release());
layout->addWidget(toolBar.release());
layout->addWidget(mapWidget);
layout->addWidget(toolBar);
}
widget->setLayout(layout.release());
setCentralWidget(widget.release());
setCentralWidget(widget);
}
void MainView::InitDocks()
{
m_samplesTable = my::make_unique<QTableView>(this /* parent */);
m_samplesTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_samplesTable->setSelectionMode(QAbstractItemView::SingleSelection);
m_samplesView = new SamplesView(this /* parent */);
{
auto * header = m_samplesTable->horizontalHeader();
header->setStretchLastSection(true /* stretch */);
header->hide();
}
m_samplesModel =
my::make_unique<QStandardItemModel>(0 /* rows */, 1 /* columns */, this /* parent */);
m_samplesTable->setModel(m_samplesModel.get());
{
auto * model = m_samplesTable->selectionModel();
auto * model = m_samplesView->selectionModel();
connect(model, SIGNAL(selectionChanged(QItemSelection const &, QItemSelection const &)), this,
SLOT(OnSampleSelected(QItemSelection const &)));
}
m_samplesDock = my::make_unique<QDockWidget>(tr("Samples"), this /* parent */, Qt::Widget);
m_samplesDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
m_samplesDock->setWidget(m_samplesTable.get());
addDockWidget(Qt::RightDockWidgetArea, m_samplesDock.get());
m_samplesDock = CreateDock("Samples", *m_samplesView);
addDockWidget(Qt::RightDockWidgetArea, m_samplesDock);
m_sampleView = new SampleView(this /* parent */);
m_sampleDock = CreateDock("Sample", *m_sampleView);
addDockWidget(Qt::RightDockWidgetArea, m_sampleDock);
}
void MainView::Open()
@ -162,3 +159,11 @@ void MainView::Open()
m_model->Open(file);
}
QDockWidget * MainView::CreateDock(std::string const & title, QWidget & widget)
{
auto * dock = new QDockWidget(ToQString(title), this /* parent */, Qt::Widget);
dock->setFeatures(QDockWidget::AllDockWidgetFeatures);
dock->setWidget(&widget);
return dock;
}

View file

@ -2,14 +2,13 @@
#include "search/search_quality/assessment_tool/view.hpp"
#include <QtGui/QStandardItemModel>
#include <QtWidgets/QDockWidget>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QTableView>
#include <memory>
class Framework;
class QDockWidget;
class QItemSelection;
class SamplesView;
class SampleView;
namespace qt
{
@ -19,8 +18,6 @@ class MapWidget;
}
}
class Framework;
class MainView : public QMainWindow, public View
{
Q_OBJECT
@ -32,21 +29,26 @@ public:
// View overrides:
void SetSamples(std::vector<search::Sample> const & samples) override;
void ShowSample(search::Sample const & sample) override;
void ShowResults(search::Results::Iter begin, search::Results::Iter end) override;
void ShowError(std::string const & msg) override;
private Q_SLOTS:
void OnSampleSelected(QItemSelection const & current);
private:
void InitMenuBar();
void InitMapWidget();
void InitDocks();
void InitMenuBar();
void Open();
QDockWidget * CreateDock(std::string const & title, QWidget & widget);
Framework & m_framework;
std::unique_ptr<QStandardItemModel> m_samplesModel;
std::unique_ptr<QTableView> m_samplesTable;
std::unique_ptr<QDockWidget> m_samplesDock;
SamplesView * m_samplesView = nullptr;
QDockWidget * m_samplesDock = nullptr;
SampleView * m_sampleView = nullptr;
QDockWidget * m_sampleDock = nullptr;
};

View file

@ -0,0 +1,106 @@
#include "search/search_quality/assessment_tool/sample_view.hpp"
#include "search/result.hpp"
#include "search/search_quality/assessment_tool/helpers.hpp"
#include "search/search_quality/assessment_tool/languages_list.hpp"
#include "search/search_quality/sample.hpp"
#include <QtGui/QStandardItem>
#include <QtGui/QStandardItemModel>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QVBoxLayout>
namespace
{
QWidget * CreateSampleWidget(QWidget & parent, search::Result const & result)
{
auto * widget = new QWidget(&parent);
auto * layout = new QVBoxLayout(widget);
widget->setLayout(layout);
layout->addWidget(new QLabel(ToQString(result.GetString())));
if (result.GetResultType() == search::Result::RESULT_FEATURE && !result.GetFeatureType().empty())
{
auto * type = new QLabel(ToQString(result.GetFeatureType()), widget);
type->setStyleSheet("QLabel { font-size : 8pt }");
layout->addWidget(type);
}
if (!result.GetAddress().empty())
{
auto * address = new QLabel(ToQString(result.GetAddress()), widget);
address->setStyleSheet("QLabel { color : green ; font-size : 8pt }");
layout->addWidget(address);
}
return widget;
}
} // namespace
SampleView::SampleView(QWidget * parent) : QWidget(parent)
{
auto * mainLayout = BuildLayoutWithoutMargins<QVBoxLayout>(this /* parent */);
{
auto * box = new QWidget(this /* parent */);
auto * layout = BuildLayoutWithoutMargins<QHBoxLayout>(box /* parent */);
box->setLayout(layout);
m_query = new QLineEdit(this /* parent */);
m_query->setToolTip(tr("Query text"));
layout->addWidget(m_query);
m_langs = new LanguagesList(this /* parent */);
m_langs->setToolTip(tr("Query input language"));
layout->addWidget(m_langs);
mainLayout->addWidget(box);
}
{
auto * box = new QWidget(this /* parent */);
auto * layout = BuildLayoutWithoutMargins<QVBoxLayout>(box /* parent */);
box->setLayout(layout);
layout->addWidget(new QLabel(tr("Found results")));
m_results = new QListWidget(box /* parent */);
layout->addWidget(m_results);
mainLayout->addWidget(box);
}
setLayout(mainLayout);
setWindowTitle(tr("Sample"));
}
void SampleView::SetContents(search::Sample const & sample)
{
m_query->setText(ToQString(sample.m_query));
m_query->home(false /* mark */);
m_langs->Select(sample.m_locale);
m_results->clear();
}
void SampleView::ShowResults(search::Results::Iter begin, search::Results::Iter end)
{
for (auto it = begin; it != end; ++it)
{
auto * item = new QListWidgetItem(m_results);
m_results->addItem(item);
auto * widget = CreateSampleWidget(*m_results /* parent */, *it /* sample */);
item->setSizeHint(widget->minimumSizeHint());
m_results->setItemWidget(item, widget);
}
}

View file

@ -0,0 +1,28 @@
#pragma once
#include "search/result.hpp"
#include <QtWidgets/QWidget>
class LanguagesList;
class QLineEdit;
class QListWidget;
namespace search
{
struct Sample;
}
class SampleView : public QWidget
{
public:
explicit SampleView(QWidget * parent);
void SetContents(search::Sample const & sample);
void ShowResults(search::Results::Iter begin, search::Results::Iter end);
private:
QLineEdit * m_query = nullptr;
LanguagesList * m_langs = nullptr;
QListWidget * m_results = nullptr;
};

View file

@ -0,0 +1,29 @@
#include "search/search_quality/assessment_tool/samples_view.hpp"
#include "search/search_quality/assessment_tool/helpers.hpp"
#include <QtGui/QStandardItem>
#include <QtGui/QStandardItemModel>
#include <QtWidgets/QHeaderView>
SamplesView::SamplesView(QWidget * parent) : QTableView(parent)
{
setEditTriggers(QAbstractItemView::NoEditTriggers);
setSelectionMode(QAbstractItemView::SingleSelection);
{
auto * header = horizontalHeader();
header->setStretchLastSection(true /* stretch */);
header->hide();
}
m_model = new QStandardItemModel(0 /* rows */, 1 /* columns */, this /* parent */);
setModel(m_model);
}
void SamplesView::SetSamples(std::vector<search::Sample> const & samples)
{
m_model->removeRows(0, m_model->rowCount());
for (auto const & sample : samples)
m_model->appendRow(new QStandardItem(ToQString(sample.m_query)));
}

View file

@ -0,0 +1,20 @@
#pragma once
#include "search/search_quality/sample.hpp"
#include <vector>
#include <QtWidgets/QTableView>
class QStandardItemModel;
class SamplesView : public QTableView
{
public:
explicit SamplesView(QWidget * parent);
void SetSamples(std::vector<search::Sample> const & samples);
private:
QStandardItemModel * m_model = nullptr;
};

View file

@ -1,5 +1,6 @@
#pragma once
#include "search/result.hpp"
#include "search/search_quality/sample.hpp"
#include <string>
@ -16,6 +17,7 @@ public:
virtual void SetSamples(std::vector<search::Sample> const & samples) = 0;
virtual void ShowSample(search::Sample const & sample) = 0;
virtual void ShowResults(search::Results::Iter begin, search::Results::Iter end) = 0;
virtual void ShowError(std::string const & msg) = 0;
protected: