[editor] Better GetEditableProperties implementation.

This commit is contained in:
Alex Zolotarev 2016-02-12 21:50:43 +03:00 committed by Sergey Yershov
parent aad9bc9bc6
commit 0ac3f7c5b0
7 changed files with 58 additions and 83 deletions

View file

@ -46,13 +46,12 @@ JNIEXPORT jintArray JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetEditableMetadata(JNIEnv * env, jclass clazz)
{
auto const * feature = activeFeature();
auto const & editableTypes = feature ? Editor::Instance().EditableMetadataForType(*feature)
: vector<Metadata::EType>{};
int const size = editableTypes.size();
auto const editable = feature ? Editor::Instance().GetEditableProperties(*feature) : osm::EditableProperties();
int const size = editable.m_metadata.size();
jintArray jEditableTypes = env->NewIntArray(size);
jint * arr = env->GetIntArrayElements(jEditableTypes, 0);
for (int i = 0; i < size; i++)
arr[i] = static_cast<jint>(editableTypes[i]);
arr[i] = static_cast<jint>(editable.m_metadata[i]);
env->ReleaseIntArrayElements(jEditableTypes, arr, 0);
return jEditableTypes;
@ -62,14 +61,14 @@ JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeIsAddressEditable(JNIEnv * env, jclass clazz)
{
auto const * feature = activeFeature();
return feature && Editor::Instance().IsAddressEditable(*feature);
return feature && Editor::Instance().GetEditableProperties(*feature).m_address;
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeIsNameEditable(JNIEnv * env, jclass clazz)
{
auto const * feature = activeFeature();
return feature && Editor::Instance().IsNameEditable(*feature);
return feature && Editor::Instance().GetEditableProperties(*feature).m_name;
}
JNIEXPORT void JNICALL

View file

@ -45,11 +45,6 @@ bool BaseChecker::operator() (vector<uint32_t> const & types) const
return false;
}
bool BaseChecker::HasTypeValue(uint32_t const type) const
{
return find(m_types.begin(), m_types.end(), type) != m_types.end();
}
IsPeakChecker::IsPeakChecker()
{
Classificator const & c = classif();

View file

@ -30,8 +30,6 @@ public:
bool operator() (feature::TypesHolder const & types) const;
bool operator() (FeatureType const & ft) const;
bool operator() (vector<uint32_t> const & types) const;
// Simple type equality comparison. No magic like in IsMatched.
bool HasTypeValue(uint32_t const type) const;
static uint32_t PrepareToMatch(uint32_t type, uint8_t level);
};

View file

@ -445,7 +445,7 @@ void Editor::Save(string const & fullFilePath) const
if (doc)
{
auto const & tmpFileName = fullFilePath + ".tmp";
string const tmpFileName = fullFilePath + ".tmp";
if (!doc.save_file(tmpFileName.data(), " "))
LOG(LERROR, ("Can't save map edits into", tmpFileName));
else if (!my::RenameFileX(tmpFileName, fullFilePath))
@ -619,63 +619,45 @@ vector<uint32_t> Editor::GetFeaturesByStatus(MwmSet::MwmId const & mwmId, Featur
return features;
}
vector<Metadata::EType> Editor::EditableMetadataForType(FeatureType const & feature) const
EditableProperties Editor::GetEditableProperties(FeatureType const & feature) const
{
// TODO(mgsergio): Load editable fields into memory from XML and query them here.
// TODO(mgsergio): Load editable fields into memory from XML config and query them here.
EditableProperties editable;
feature::TypesHolder const types(feature);
set<Metadata::EType> fields;
auto const & isBuilding = ftypes::IsBuildingChecker::Instance();
for (auto type : types)
for (uint32_t const type : types)
{
// TODO(mgsergio): If some fields for one type are marked as "NOT edited" in the config,
// they should have priority over same "edited" fields in other feature's types.
auto const * desc = GetTypeDescription(type);
if (desc)
{
for (auto field : desc->m_fields)
fields.insert(field);
// If address is editable, many metadata fields are editable too.
if (desc->m_address)
{
fields.insert(EType::FMD_EMAIL);
fields.insert(EType::FMD_OPEN_HOURS);
fields.insert(EType::FMD_PHONE_NUMBER);
fields.insert(EType::FMD_WEBSITE);
}
}
else if (isBuilding.HasTypeValue(type))
{
// Post boxes and post offices have editable postcode field defined separately.
fields.insert(EType::FMD_POSTCODE);
editable.m_name = desc->m_name;
editable.m_address = desc->m_address;
for (EType const field : desc->m_fields)
editable.m_metadata.push_back(field);
}
}
return {begin(fields), end(fields)};
}
// Buildings are processed separately.
// TODO(mgsergio): Activate this code by XML config variable.
if (ftypes::IsBuildingChecker::Instance()(feature))
editable.m_address = true;
bool Editor::IsNameEditable(FeatureType const & feature) const
{
feature::TypesHolder const types(feature);
for (auto type : types)
// If address is editable, many metadata fields are editable too.
if (editable.m_address)
{
auto const * typeDesc = GetTypeDescription(type);
if (typeDesc && typeDesc->m_name)
return true;
// TODO(mgsergio): Load address-related editable properties from XML config.
editable.m_metadata.push_back(EType::FMD_EMAIL);
editable.m_metadata.push_back(EType::FMD_OPEN_HOURS);
editable.m_metadata.push_back(EType::FMD_PHONE_NUMBER);
editable.m_metadata.push_back(EType::FMD_WEBSITE);
// Post boxes and post offices should have editable postcode field defined separately.
editable.m_metadata.push_back(EType::FMD_POSTCODE);
}
return false;
}
bool Editor::IsAddressEditable(FeatureType const & feature) const
{
feature::TypesHolder const types(feature);
auto & isBuilding = ftypes::IsBuildingChecker::Instance();
for (auto type : types)
{
// Building addresses are always editable.
if (isBuilding.HasTypeValue(type))
return true;
auto const * typeDesc = GetTypeDescription(type);
if (typeDesc && typeDesc->m_address)
return true;
}
return false;
// Avoid possible duplicates.
my::SortUnique(editable.m_metadata);
return editable;
}
bool Editor::HaveSomethingToUpload() const

View file

@ -13,11 +13,20 @@
#include "std/ctime.hpp"
#include "std/function.hpp"
#include "std/map.hpp"
#include "std/set.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"
namespace osm
{
/// Holds information to construct editor's UI.
struct EditableProperties
{
bool m_name = false;
bool m_address = false;
vector<feature::Metadata::EType> m_metadata;
bool IsEditable() const { return m_name || m_address || !m_metadata.empty(); }
};
class Editor final
{
Editor() = default;
@ -93,11 +102,7 @@ public:
string const & editedStreet = "",
string const & editedHouseNumber = "");
vector<feature::Metadata::EType> EditableMetadataForType(FeatureType const & feature) const;
/// @returns true if feature's name is editable.
bool IsNameEditable(FeatureType const & feature) const;
/// @returns true if street and house number are editable.
bool IsAddressEditable(FeatureType const & feature) const;
EditableProperties GetEditableProperties(FeatureType const & feature) const;
bool HaveSomethingToUpload() const;
using TChangesetTags = map<string, string>;

View file

@ -349,20 +349,17 @@ void initFieldsMap()
if (!feature)
return;
auto & editor = osm::Editor::Instance();
vector<Metadata::EType> const editableTypes = editor.EditableMetadataForType(*feature);
bool const isNameEditable = editor.IsNameEditable(*feature);
bool const isAddressEditable = editor.IsAddressEditable(*feature);
if (!editableTypes.empty() || isAddressEditable || isNameEditable)
osm::EditableProperties const editable = osm::Editor::Instance().GetEditableProperties(*feature);
if (editable.IsEditable())
[self addEditField];
if (isNameEditable)
if (editable.m_name)
m_editableFields.insert(MWMPlacePageCellTypeName);
if (isAddressEditable)
if (editable.m_address)
{
m_editableFields.insert(MWMPlacePageCellTypeStreet);
m_editableFields.insert(MWMPlacePageCellTypeBuilding);
}
for (auto const & type : editableTypes)
for (feature::Metadata::EType const type : editable.m_metadata)
{
NSAssert(kMetaFieldsMap[type] >= Metadata::FMD_COUNT || kMetaFieldsMap[type] == 0, @"Incorrect enum value");
MWMPlacePageCellType const field = static_cast<MWMPlacePageCellType>(kMetaFieldsMap[type]);

View file

@ -56,14 +56,15 @@ EditorDialog::EditorDialog(QWidget * parent, FeatureType & feature, Framework &
typesRow->addWidget(new QLabel(QString::fromStdString(strTypes)));
vLayout->addLayout(typesRow);
bool const readOnlyName = !editor.IsNameEditable(feature);
osm::EditableProperties const editable = editor.GetEditableProperties(feature);
// Rows block: Name(s) label(s) and text input.
char const * defaultLangStr = StringUtf8Multilang::GetLangByCode(StringUtf8Multilang::DEFAULT_CODE);
// Default name editor is always displayed, even if feature name is empty.
QHBoxLayout * defaultNameRow = new QHBoxLayout();
defaultNameRow->addWidget(new QLabel(QString("name")));
QLineEdit * defaultNamelineEdit = new QLineEdit();
defaultNamelineEdit->setReadOnly(readOnlyName);
defaultNamelineEdit->setReadOnly(!editable.m_name);
defaultNamelineEdit->setObjectName(defaultLangStr);
defaultNameRow->addWidget(defaultNamelineEdit);
vLayout->addLayout(defaultNameRow);
@ -78,7 +79,7 @@ EditorDialog::EditorDialog(QWidget * parent, FeatureType & feature, Framework &
char const * langStr = StringUtf8Multilang::GetLangByCode(langCode);
nameRow->addWidget(new QLabel(QString("name:") + langStr));
QLineEdit * lineEditName = new QLineEdit(QString::fromStdString(name));
lineEditName->setReadOnly(readOnlyName);
lineEditName->setReadOnly(!editable.m_name);
lineEditName->setObjectName(langStr);
nameRow->addWidget(lineEditName);
vLayout->addLayout(nameRow);
@ -87,7 +88,6 @@ EditorDialog::EditorDialog(QWidget * parent, FeatureType & feature, Framework &
});
// Address rows.
bool const readOnlyAddress = !editor.IsAddressEditable(feature);
vector<string> nearbyStreets = frm.GetNearbyFeatureStreets(feature);
// If feature does not have a specified street, display empty combo box.
search::AddressInfo const info = frm.GetFeatureAddressInfo(feature);
@ -98,24 +98,23 @@ EditorDialog::EditorDialog(QWidget * parent, FeatureType & feature, Framework &
QComboBox * cmb = new QComboBox();
for (auto const & street : nearbyStreets)
cmb->addItem(street.c_str());
cmb->setEditable(!readOnlyAddress);
cmb->setEnabled(!readOnlyAddress);
cmb->setEditable(editable.m_address);
cmb->setEnabled(editable.m_address);
cmb->setObjectName(kStreetObjectName);
streetRow->addWidget(cmb) ;
streetRow->addWidget(cmb);
vLayout->addLayout(streetRow);
QHBoxLayout * houseRow = new QHBoxLayout();
houseRow->addWidget(new QLabel(QString(kHouseNumberObjectName)));
QLineEdit * houseLineEdit = new QLineEdit();
houseLineEdit->setText(info.m_house.c_str());
houseLineEdit->setReadOnly(readOnlyAddress);
houseLineEdit->setReadOnly(!editable.m_address);
houseLineEdit->setObjectName(kHouseNumberObjectName);
houseRow->addWidget(houseLineEdit);
vLayout->addLayout(houseRow);
// All metadata rows.
QVBoxLayout * metaRows = new QVBoxLayout();
vector<Metadata::EType> const editableMetadataFields = editor.EditableMetadataForType(feature);
for (Metadata::EType const field : editableMetadataFields)
for (Metadata::EType const field : editable.m_metadata)
{
QString const fieldName = QString::fromStdString(DebugPrint(field));
QHBoxLayout * fieldRow = new QHBoxLayout();