forked from organicmaps/organicmaps
[assessment-tool] Editing support for relevances.
This commit is contained in:
parent
27bfae72bd
commit
fe91d6e759
8 changed files with 215 additions and 19 deletions
|
@ -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
|
||||
|
|
66
search/search_quality/assessment_tool/edits.cpp
Normal file
66
search/search_quality/assessment_tool/edits.cpp
Normal 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(); }
|
67
search/search_quality/assessment_tool/edits.hpp
Normal file
67
search/search_quality/assessment_tool/edits.hpp
Normal 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;
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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("");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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()); }
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue