[assessment-tool] Editing support for relevances.

This commit is contained in:
Yuri Gorshenin 2017-03-22 18:44:24 +03:00 committed by Vladimir Byko-Ianko
parent 27bfae72bd
commit fe91d6e759
8 changed files with 215 additions and 19 deletions

View file

@ -9,6 +9,8 @@ include_directories(${OMIM_ROOT}/3party/glm)
set(
SRC
assessment_tool.cpp
edits.cpp
edits.hpp
helpers.cpp
helpers.hpp
languages_list.cpp

View file

@ -0,0 +1,66 @@
#include "search/search_quality/assessment_tool/edits.hpp"
#include "base/assert.hpp"
// Edits::RelevanceEditor --------------------------------------------------------------------------
Edits::RelevanceEditor::RelevanceEditor(Edits & parent, size_t index)
: m_parent(&parent), m_index(index)
{
}
bool Edits::RelevanceEditor::Set(Relevance relevance)
{
CHECK(IsValid(), ());
return m_parent->UpdateRelevance(m_index, relevance);
}
Edits::Relevance Edits::RelevanceEditor::Get() const
{
CHECK(IsValid(), ());
auto const & relevances = m_parent->GetRelevances();
CHECK_LESS(m_index, relevances.size(), ());
return relevances[m_index];
}
// Edits -------------------------------------------------------------------------------------------
Edits::Edits(Delegate & delegate) : m_delegate(delegate) {}
void Edits::ResetRelevances(std::vector<Relevance> const & relevances)
{
WithDelegate([this, &relevances]() {
m_origRelevances = relevances;
m_currRelevances = relevances;
m_relevanceEdits.clear();
});
}
bool Edits::UpdateRelevance(size_t index, Relevance relevance)
{
return WithDelegate([this, index, relevance]() {
CHECK_LESS(index, m_currRelevances.size(), ());
m_currRelevances[index] = relevance;
CHECK_EQUAL(m_currRelevances.size(), m_origRelevances.size(), ());
if (m_currRelevances[index] != m_origRelevances[index])
{
m_relevanceEdits.insert(index);
return true;
}
else
{
m_relevanceEdits.erase(index);
return false;
}
});
}
void Edits::Clear()
{
WithDelegate([this]() {
m_origRelevances.clear();
m_currRelevances.clear();
m_relevanceEdits.clear();
});
}
bool Edits::HasChanges() const { return !m_relevanceEdits.empty(); }

View file

@ -0,0 +1,67 @@
#pragma once
#include "search/search_quality/sample.hpp"
#include "base/scope_guard.hpp"
#include <set>
#include <type_traits>
#include <vector>
class Edits
{
public:
using Relevance = search::Sample::Result::Relevance;
class RelevanceEditor
{
public:
RelevanceEditor() = default;
RelevanceEditor(Edits & parent, size_t index);
bool IsValid() const { return m_parent != nullptr; }
// Sets relevance to |relevance|. Returns true iff |relevance|
// differs from the original one.
bool Set(Relevance relevance);
Relevance Get() const;
private:
Edits * m_parent = nullptr;
size_t m_index = 0;
};
struct Delegate
{
virtual ~Delegate() = default;
virtual void OnUpdate() = 0;
};
Edits(Delegate & delegate);
void ResetRelevances(std::vector<Relevance> const & relevances);
// Sets relevance at |index| to |relevance|. Returns true iff
// |relevance| differs from the original one.
bool UpdateRelevance(size_t index, Relevance relevance);
std::vector<Relevance> const & GetRelevances() { return m_currRelevances; }
void Clear();
bool HasChanges() const;
private:
template <typename Fn>
typename std::result_of<Fn()>::type WithDelegate(Fn && fn)
{
MY_SCOPE_GUARD(cleanup, [this]() { m_delegate.OnUpdate(); });
return fn();
}
Delegate & m_delegate;
std::vector<Relevance> m_origRelevances;
std::vector<Relevance> m_currRelevances;
std::set<size_t> m_relevanceEdits;
};

View file

@ -151,6 +151,12 @@ void MainView::InitDocks()
m_sampleView = new SampleView(this /* parent */);
m_sampleDock = CreateDock("Sample", *m_sampleView);
connect(m_sampleView, &SampleView::EditStateUpdated, this, [this](bool hasEdits) {
if (hasEdits)
m_sampleDock->setWindowTitle(tr("Sample *"));
else
m_sampleDock->setWindowTitle(tr("Sample"));
});
addDockWidget(Qt::RightDockWidgetArea, m_sampleDock);
}

View file

@ -10,8 +10,6 @@
#include <QtWidgets/QRadioButton>
#include <QtWidgets/QVBoxLayout>
using Relevance = search::Sample::Result::Relevance;
namespace
{
QLabel * CreateLabel(QWidget & parent)
@ -38,19 +36,29 @@ ResultView::ResultView(search::Result const & result, QWidget & parent) : QWidge
{
Init();
SetContents(result);
setEnabled(false);
setObjectName("result");
}
void ResultView::SetRelevance(Relevance relevance)
void ResultView::EnableEditing(Edits::RelevanceEditor editor)
{
if (!editor.IsValid())
return;
m_editor = editor;
m_irrelevant->setChecked(false);
m_relevant->setChecked(false);
m_vital->setChecked(false);
switch (relevance)
switch (m_editor.Get())
{
case Relevance::Irrelevant: m_irrelevant->setChecked(true); break;
case Relevance::Relevant: m_relevant->setChecked(true); break;
case Relevance::Vital: m_vital->setChecked(true); break;
}
setEnabled(true);
}
void ResultView::Init()
@ -75,13 +83,9 @@ void ResultView::Init()
auto * groupLayout = new QHBoxLayout(group /* parent */);
group->setLayout(groupLayout);
m_irrelevant = new QRadioButton("0", this /* parent */);
m_relevant = new QRadioButton("+1", this /* parent */);
m_vital = new QRadioButton("+2", this /* parent */);
groupLayout->addWidget(m_irrelevant);
groupLayout->addWidget(m_relevant);
groupLayout->addWidget(m_vital);
m_irrelevant = CreateRatioButton("0", *groupLayout);
m_relevant = CreateRatioButton("+1", *groupLayout);
m_vital = CreateRatioButton("+2", *groupLayout);
layout->addWidget(group);
}
@ -97,3 +101,32 @@ void ResultView::SetContents(search::Result const & result)
m_relevant->setChecked(false);
m_vital->setChecked(false);
}
QRadioButton * ResultView::CreateRatioButton(string const & text, QLayout & layout)
{
QRadioButton * radio = new QRadioButton(QString::fromStdString(text), this /* parent */);
layout.addWidget(radio);
connect(radio, &QRadioButton::toggled, this, &ResultView::OnRelevanceChanged);
return radio;
}
void ResultView::OnRelevanceChanged()
{
if (!m_editor.IsValid())
return;
auto relevance = Relevance::Irrelevant;
if (m_irrelevant->isChecked())
relevance = Relevance::Irrelevant;
else if (m_relevant->isChecked())
relevance = Relevance::Relevant;
else if (m_vital->isChecked())
relevance = Relevance::Vital;
bool changed = m_editor.Set(relevance);
if (changed)
setStyleSheet("#result {background: rgba(255, 255, 200, 50%)}");
else
setStyleSheet("");
}

View file

@ -1,5 +1,6 @@
#pragma once
#include "search/search_quality/assessment_tool/edits.hpp"
#include "search/search_quality/sample.hpp"
#include <QtWidgets/QWidget>
@ -15,14 +16,19 @@ class Result;
class ResultView : public QWidget
{
public:
using Relevance = search::Sample::Result::Relevance;
ResultView(search::Result const & result, QWidget & parent);
void SetRelevance(search::Sample::Result::Relevance relevance);
void EnableEditing(Edits::RelevanceEditor editor);
private:
void Init();
void SetContents(search::Result const & result);
QRadioButton * CreateRatioButton(string const & label, QLayout & layout);
void OnRelevanceChanged();
QLabel * m_string = nullptr;
QLabel * m_type = nullptr;
QLabel * m_address = nullptr;
@ -30,4 +36,6 @@ private:
QRadioButton * m_irrelevant = nullptr;
QRadioButton * m_relevant = nullptr;
QRadioButton * m_vital = nullptr;
Edits::RelevanceEditor m_editor;
};

View file

@ -17,9 +17,7 @@
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QVBoxLayout>
using Relevance = search::Sample::Result::Relevance;
SampleView::SampleView(QWidget * parent) : QWidget(parent)
SampleView::SampleView(QWidget * parent) : QWidget(parent), m_edits(*this /* delegate */)
{
auto * mainLayout = BuildLayoutWithoutMargins<QVBoxLayout>(this /* parent */);
@ -53,7 +51,6 @@ SampleView::SampleView(QWidget * parent) : QWidget(parent)
}
setLayout(mainLayout);
setWindowTitle(tr("Sample"));
}
void SampleView::SetContents(search::Sample const & sample)
@ -75,6 +72,10 @@ void SampleView::ShowResults(search::Results::Iter begin, search::Results::Iter
void SampleView::SetResultRelevances(std::vector<Relevance> const & relevances)
{
CHECK_EQUAL(relevances.size(), m_results->Size(), ());
m_edits.ResetRelevances(relevances);
for (size_t i = 0; i < relevances.size(); ++i)
m_results->Get(i).SetRelevance(relevances[i]);
m_results->Get(i).EnableEditing(Edits::RelevanceEditor(m_edits, i));
}
void SampleView::OnUpdate() { emit EditStateUpdated(m_edits.HasChanges()); }

View file

@ -1,6 +1,7 @@
#pragma once
#include "search/result.hpp"
#include "search/search_quality/assessment_tool/edits.hpp"
#include "search/search_quality/sample.hpp"
#include <QtWidgets/QWidget>
@ -9,17 +10,29 @@ class LanguagesList;
class QLineEdit;
class ResultsView;
class SampleView : public QWidget
class SampleView : public QWidget, public Edits::Delegate
{
Q_OBJECT
public:
using Relevance = search::Sample::Result::Relevance;
explicit SampleView(QWidget * parent);
void SetContents(search::Sample const & sample);
void ShowResults(search::Results::Iter begin, search::Results::Iter end);
void SetResultRelevances(std::vector<search::Sample::Result::Relevance> const & relevances);
void SetResultRelevances(std::vector<Relevance> const & relevances);
// Edits::Delegate overrides:
void OnUpdate();
signals:
void EditStateUpdated(bool hasEdits);
private:
QLineEdit * m_query = nullptr;
LanguagesList * m_langs = nullptr;
ResultsView * m_results = nullptr;
Edits m_edits;
};