diff --git a/android/jni/com/mapswithme/maps/editor/Editor.cpp b/android/jni/com/mapswithme/maps/editor/Editor.cpp index af37d16d73..91a98045f8 100644 --- a/android/jni/com/mapswithme/maps/editor/Editor.cpp +++ b/android/jni/com/mapswithme/maps/editor/Editor.cpp @@ -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{}; - 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(editableTypes[i]); + arr[i] = static_cast(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 diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index 9dad8933bb..798a168fca 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -45,11 +45,6 @@ bool BaseChecker::operator() (vector 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(); diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp index 48bb6348fd..e767abbb4f 100644 --- a/indexer/ftypes_matcher.hpp +++ b/indexer/ftypes_matcher.hpp @@ -30,8 +30,6 @@ public: bool operator() (feature::TypesHolder const & types) const; bool operator() (FeatureType const & ft) const; bool operator() (vector 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); }; diff --git a/indexer/osm_editor.cpp b/indexer/osm_editor.cpp index a39103e941..15d87e2600 100644 --- a/indexer/osm_editor.cpp +++ b/indexer/osm_editor.cpp @@ -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 Editor::GetFeaturesByStatus(MwmSet::MwmId const & mwmId, Featur return features; } -vector 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 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 diff --git a/indexer/osm_editor.hpp b/indexer/osm_editor.hpp index 4339517cf4..6ddbe1e425 100644 --- a/indexer/osm_editor.hpp +++ b/indexer/osm_editor.hpp @@ -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 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 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; diff --git a/iphone/Maps/Classes/MWMPlacePageEntity.mm b/iphone/Maps/Classes/MWMPlacePageEntity.mm index e152707221..d1636a4347 100644 --- a/iphone/Maps/Classes/MWMPlacePageEntity.mm +++ b/iphone/Maps/Classes/MWMPlacePageEntity.mm @@ -349,20 +349,17 @@ void initFieldsMap() if (!feature) return; - auto & editor = osm::Editor::Instance(); - vector 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(kMetaFieldsMap[type]); diff --git a/qt/editor_dialog.cpp b/qt/editor_dialog.cpp index b6add86099..f2735d627d 100644 --- a/qt/editor_dialog.cpp +++ b/qt/editor_dialog.cpp @@ -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 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 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();