forked from organicmaps/organicmaps
[search] Implemented samples loading.
This commit is contained in:
parent
b25b0f0c08
commit
193c703eb0
8 changed files with 331 additions and 82 deletions
|
@ -1,9 +1,22 @@
|
|||
project(assessment_tool)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
include_directories(${OMIM_ROOT}/3party/gflags/src)
|
||||
include_directories(${OMIM_ROOT}/3party/glm)
|
||||
|
||||
set(SRC assessment_tool.cc)
|
||||
set(
|
||||
SRC
|
||||
assessment_tool.cc
|
||||
main_model.cpp
|
||||
main_model.hpp
|
||||
main_model.hpp
|
||||
main_view.cpp
|
||||
main_view.hpp
|
||||
model.hpp
|
||||
view.hpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SRC})
|
||||
|
||||
|
|
|
@ -1,96 +1,21 @@
|
|||
#include "qt/qt_common/helpers.hpp"
|
||||
#include "qt/qt_common/map_widget.hpp"
|
||||
#include "qt/qt_common/scale_slider.hpp"
|
||||
|
||||
#include "map/framework.hpp"
|
||||
#include "search/search_quality/assessment_tool/main_model.hpp"
|
||||
#include "search/search_quality/assessment_tool/main_view.hpp"
|
||||
|
||||
#include "search/search_quality/helpers.hpp"
|
||||
|
||||
#include "map/framework.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <QtCore/Qt>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QToolBar>
|
||||
|
||||
#include "3party/gflags/src/gflags/gflags.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
DEFINE_string(resources_path, "", "Path to resources directory");
|
||||
DEFINE_string(data_path, "", "Path to data directory");
|
||||
|
||||
namespace
|
||||
{
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
public:
|
||||
MainWindow(Framework & framework) : m_framework(framework)
|
||||
{
|
||||
setWindowTitle(tr("Assessment tool"));
|
||||
InitMenuBar();
|
||||
InitMapWidget();
|
||||
}
|
||||
|
||||
private:
|
||||
void InitMenuBar()
|
||||
{
|
||||
auto * bar = menuBar();
|
||||
|
||||
auto * fileMenu = bar->addMenu(tr("&File"));
|
||||
|
||||
{
|
||||
auto open = make_unique<QAction>(tr("&Open queries..."), this);
|
||||
open->setShortcuts(QKeySequence::Open);
|
||||
open->setStatusTip(tr("Open the file with queries for assessment"));
|
||||
connect(open.get(), &QAction::triggered, this, &MainWindow::Open);
|
||||
fileMenu->addAction(open.release());
|
||||
}
|
||||
|
||||
fileMenu->addSeparator();
|
||||
|
||||
{
|
||||
auto quit = make_unique<QAction>(tr("&Quit"), this);
|
||||
quit->setShortcuts(QKeySequence::Quit);
|
||||
quit->setStatusTip(tr("Exit the tool"));
|
||||
connect(quit.get(), &QAction::triggered, this, &QWidget::close);
|
||||
fileMenu->addAction(quit.release());
|
||||
}
|
||||
}
|
||||
|
||||
void InitMapWidget()
|
||||
{
|
||||
auto widget = make_unique<qt::common::MapWidget>(m_framework, this);
|
||||
widget->BindHotkeys(*this);
|
||||
InitToolBar(*widget);
|
||||
setCentralWidget(widget.release());
|
||||
}
|
||||
|
||||
void InitToolBar(qt::common::MapWidget & widget)
|
||||
{
|
||||
auto toolBar = make_unique<QToolBar>(this);
|
||||
toolBar->setOrientation(Qt::Vertical);
|
||||
toolBar->setIconSize(QSize(32, 32));
|
||||
qt::common::ScaleSlider::Embed(Qt::Vertical, *toolBar, widget);
|
||||
addToolBar(Qt::RightToolBarArea, toolBar.release());
|
||||
}
|
||||
|
||||
void Open()
|
||||
{
|
||||
auto const file = QFileDialog::getOpenFileName(this, tr("Open queries..."), QString(),
|
||||
tr("JSON files (*.json)"))
|
||||
.toStdString();
|
||||
if (file.empty())
|
||||
return;
|
||||
// TODO (@y): implement this
|
||||
}
|
||||
|
||||
Framework & m_framework;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
|
@ -110,7 +35,12 @@ int main(int argc, char ** argv)
|
|||
QApplication app(argc, argv);
|
||||
|
||||
Framework framework;
|
||||
MainWindow window(framework);
|
||||
window.show();
|
||||
MainView view(framework);
|
||||
MainModel model;
|
||||
|
||||
model.SetView(view);
|
||||
view.SetModel(model);
|
||||
|
||||
view.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
|
44
search/search_quality/assessment_tool/main_model.cpp
Normal file
44
search/search_quality/assessment_tool/main_model.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include "search/search_quality/assessment_tool/main_model.hpp"
|
||||
|
||||
#include "search/search_quality/assessment_tool/view.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
|
||||
void MainModel::Open(std::string const & path)
|
||||
{
|
||||
CHECK(m_view, ());
|
||||
|
||||
std::ifstream ifs(path);
|
||||
if (!ifs)
|
||||
{
|
||||
m_view->ShowError("Can't open file: " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string contents;
|
||||
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
|
||||
back_inserter(contents));
|
||||
|
||||
std::vector<search::Sample> samples;
|
||||
if (!search::Sample::DeserializeFromJSON(contents, samples))
|
||||
{
|
||||
m_view->ShowError("Can't parse samples: " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
m_samples.swap(samples);
|
||||
m_view->SetSamples(m_samples);
|
||||
}
|
||||
|
||||
void MainModel::OnSampleSelected(int index)
|
||||
{
|
||||
CHECK_GREATER_OR_EQUAL(index, 0, ());
|
||||
CHECK_LESS(index, m_samples.size(), ());
|
||||
CHECK(m_view, ());
|
||||
m_view->ShowSample(m_samples[index]);
|
||||
}
|
19
search/search_quality/assessment_tool/main_model.hpp
Normal file
19
search/search_quality/assessment_tool/main_model.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "search/search_quality/assessment_tool/model.hpp"
|
||||
#include "search/search_quality/sample.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Framework;
|
||||
|
||||
class MainModel : public Model
|
||||
{
|
||||
public:
|
||||
// Model overrides:
|
||||
void Open(std::string const & path) override;
|
||||
void OnSampleSelected(int index) override;
|
||||
|
||||
private:
|
||||
std::vector<search::Sample> m_samples;
|
||||
};
|
150
search/search_quality/assessment_tool/main_view.cpp
Normal file
150
search/search_quality/assessment_tool/main_view.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
#include "search/search_quality/assessment_tool/main_view.hpp"
|
||||
|
||||
#include "search/search_quality/assessment_tool/main_model.hpp"
|
||||
|
||||
#include "qt/qt_common/map_widget.hpp"
|
||||
#include "qt/qt_common/scale_slider.hpp"
|
||||
|
||||
#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/QFileDialog>
|
||||
#include <QtWidgets/QHeaderView>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QToolBar>
|
||||
|
||||
MainView::MainView(Framework & framework) : m_framework(framework)
|
||||
{
|
||||
setWindowTitle(tr("Assessment tool"));
|
||||
InitMapWidget();
|
||||
InitDocks();
|
||||
InitMenuBar();
|
||||
}
|
||||
|
||||
void MainView::SetSamples(std::vector<search::Sample> const & samples)
|
||||
{
|
||||
m_samplesModel->removeRows(0, m_samplesModel->rowCount());
|
||||
for (size_t i = 0; i < samples.size(); ++i)
|
||||
{
|
||||
m_samplesModel->appendRow(
|
||||
new QStandardItem(QString::fromUtf8(strings::ToUtf8(samples[i].m_query).c_str())));
|
||||
}
|
||||
}
|
||||
|
||||
void MainView::ShowSample(search::Sample const & sample)
|
||||
{
|
||||
// TODO (@y): implement a dock view for search sample.
|
||||
}
|
||||
|
||||
void MainView::ShowError(std::string const & msg)
|
||||
{
|
||||
QMessageBox box(QMessageBox::Critical /* icon */, tr("Error") /* title */,
|
||||
QString::fromStdString(msg) /* text */, QMessageBox::Ok /* buttons */,
|
||||
this /* parent */);
|
||||
box.exec();
|
||||
}
|
||||
|
||||
void MainView::OnSampleSelected(QItemSelection const & current)
|
||||
{
|
||||
CHECK(m_model, ());
|
||||
auto indexes = current.indexes();
|
||||
for (auto const & index : indexes)
|
||||
m_model->OnSampleSelected(index.row());
|
||||
}
|
||||
|
||||
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);
|
||||
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());
|
||||
}
|
||||
|
||||
fileMenu->addSeparator();
|
||||
|
||||
{
|
||||
auto quit = make_unique<QAction>(tr("&Quit"), this);
|
||||
quit->setShortcuts(QKeySequence::Quit);
|
||||
quit->setStatusTip(tr("Exit the tool"));
|
||||
connect(quit.get(), &QAction::triggered, this, &QWidget::close);
|
||||
fileMenu->addAction(quit.release());
|
||||
}
|
||||
|
||||
auto * viewMenu = bar->addMenu(tr("&View"));
|
||||
{
|
||||
viewMenu->addAction(m_samplesDock->toggleViewAction());
|
||||
}
|
||||
}
|
||||
|
||||
void MainView::InitMapWidget()
|
||||
{
|
||||
auto widget = make_unique<qt::common::MapWidget>(m_framework, this);
|
||||
widget->BindHotkeys(*this);
|
||||
InitToolBar(*widget);
|
||||
setCentralWidget(widget.release());
|
||||
}
|
||||
|
||||
void MainView::InitToolBar(qt::common::MapWidget & widget)
|
||||
{
|
||||
auto toolBar = make_unique<QToolBar>(this);
|
||||
toolBar->setOrientation(Qt::Vertical);
|
||||
toolBar->setIconSize(QSize(32, 32));
|
||||
qt::common::ScaleSlider::Embed(Qt::Vertical, *toolBar, widget);
|
||||
addToolBar(Qt::RightToolBarArea, toolBar.release());
|
||||
}
|
||||
|
||||
void MainView::InitDocks()
|
||||
{
|
||||
m_samplesTable = my::make_unique<QTableView>(this /* parent */);
|
||||
m_samplesTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
m_samplesTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
{
|
||||
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();
|
||||
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());
|
||||
}
|
||||
|
||||
void MainView::Open()
|
||||
{
|
||||
CHECK(m_model, ());
|
||||
|
||||
auto const file = QFileDialog::getOpenFileName(this, tr("Open samples..."), QString(),
|
||||
tr("JSON files (*.json)"))
|
||||
.toStdString();
|
||||
if (file.empty())
|
||||
return;
|
||||
|
||||
m_model->Open(file);
|
||||
}
|
52
search/search_quality/assessment_tool/main_view.hpp
Normal file
52
search/search_quality/assessment_tool/main_view.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "search/search_quality/assessment_tool/view.hpp"
|
||||
|
||||
#include <QtGui/QStandardItemModel>
|
||||
#include <QtWidgets/QDockWidget>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QTableView>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QItemSelection;
|
||||
|
||||
namespace qt
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
class MapWidget;
|
||||
}
|
||||
}
|
||||
|
||||
class Framework;
|
||||
|
||||
class MainView : public QMainWindow, public View
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainView(Framework & framework);
|
||||
|
||||
// View overrides:
|
||||
void SetSamples(std::vector<search::Sample> const & samples) override;
|
||||
void ShowSample(search::Sample const & sample) override;
|
||||
void ShowError(std::string const & msg) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void OnSampleSelected(QItemSelection const & current);
|
||||
|
||||
private:
|
||||
void InitMenuBar();
|
||||
void InitMapWidget();
|
||||
void InitToolBar(qt::common::MapWidget & widget);
|
||||
void InitDocks();
|
||||
|
||||
void Open();
|
||||
|
||||
Framework & m_framework;
|
||||
|
||||
std::unique_ptr<QStandardItemModel> m_samplesModel;
|
||||
std::unique_ptr<QTableView> m_samplesTable;
|
||||
std::unique_ptr<QDockWidget> m_samplesDock;
|
||||
};
|
19
search/search_quality/assessment_tool/model.hpp
Normal file
19
search/search_quality/assessment_tool/model.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class View;
|
||||
|
||||
class Model
|
||||
{
|
||||
public:
|
||||
~Model() = default;
|
||||
|
||||
void SetView(View & view) { m_view = &view; }
|
||||
|
||||
virtual void Open(std::string const & path) = 0;
|
||||
virtual void OnSampleSelected(int index) = 0;
|
||||
|
||||
protected:
|
||||
View * m_view = nullptr;
|
||||
};
|
22
search/search_quality/assessment_tool/view.hpp
Normal file
22
search/search_quality/assessment_tool/view.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "search/search_quality/sample.hpp"
|
||||
|
||||
#include "std/vector.hpp"
|
||||
|
||||
class Model;
|
||||
|
||||
class View
|
||||
{
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
|
||||
void SetModel(Model & model) { m_model = &model; }
|
||||
|
||||
virtual void SetSamples(std::vector<search::Sample> const & samples) = 0;
|
||||
virtual void ShowSample(search::Sample const & sample) = 0;
|
||||
virtual void ShowError(std::string const & msg) = 0;
|
||||
|
||||
protected:
|
||||
Model * m_model = nullptr;
|
||||
};
|
Loading…
Add table
Reference in a new issue