diff --git a/drape_frontend/apply_feature_functors.cpp b/drape_frontend/apply_feature_functors.cpp index 5689b85fd4..1c23b108e7 100644 --- a/drape_frontend/apply_feature_functors.cpp +++ b/drape_frontend/apply_feature_functors.cpp @@ -269,7 +269,7 @@ ApplyPointFeature::ApplyPointFeature(TInsertShapeFn const & insertShape, Feature , m_hasPoint(false) , m_hasArea(false) , m_createdByEditor(false) - , m_deletedInEditor(false) + , m_obsoleteInEditor(false) , m_symbolDepth(dp::minDepth) , m_circleDepth(dp::minDepth) , m_symbolRule(nullptr) @@ -279,10 +279,11 @@ ApplyPointFeature::ApplyPointFeature(TInsertShapeFn const & insertShape, Feature void ApplyPointFeature::operator()(m2::PointD const & point, bool hasArea) { + auto const & editor = osm::Editor::Instance(); m_hasPoint = true; m_hasArea = hasArea; - m_createdByEditor = osm::Editor::IsCreatedFeature(m_id); - m_deletedInEditor = false; //TODO: implement + m_createdByEditor = editor.GetFeatureStatus(m_id) == osm::Editor::FeatureStatus::Created; + m_obsoleteInEditor = editor.GetFeatureStatus(m_id) == osm::Editor::FeatureStatus::Obsolete; m_centerPoint = point; } @@ -378,7 +379,7 @@ void ApplyPointFeature::Finish() params.m_posZ = m_posZ; params.m_hasArea = m_hasArea; params.m_createdByEditor = m_createdByEditor; - params.m_deletedInEditor = m_deletedInEditor; + params.m_obsoleteInEditor = m_obsoleteInEditor; m_insertShape(make_unique_dp(m_centerPoint, params)); } } diff --git a/drape_frontend/apply_feature_functors.hpp b/drape_frontend/apply_feature_functors.hpp index ba7ae590da..b2edc079bd 100644 --- a/drape_frontend/apply_feature_functors.hpp +++ b/drape_frontend/apply_feature_functors.hpp @@ -80,7 +80,7 @@ private: bool m_hasPoint; bool m_hasArea; bool m_createdByEditor; - bool m_deletedInEditor; + bool m_obsoleteInEditor; double m_symbolDepth; double m_circleDepth; SymbolRuleProto const * m_symbolRule; diff --git a/drape_frontend/poi_symbol_shape.cpp b/drape_frontend/poi_symbol_shape.cpp index 0ef9b12d41..4e796950bb 100644 --- a/drape_frontend/poi_symbol_shape.cpp +++ b/drape_frontend/poi_symbol_shape.cpp @@ -117,7 +117,7 @@ void PoiSymbolShape::Draw(ref_ptr batcher, ref_ptrSetPivotZ(m_params.m_posZ); handle->SetExtendingSize(m_params.m_extendingSize); - if (m_params.m_deletedInEditor) + if (m_params.m_obsoleteInEditor) { dp::TextureManager::ColorRegion maskColorRegion; textures->GetColorRegion(kDeletedColorMask, maskColorRegion); @@ -134,7 +134,7 @@ uint64_t PoiSymbolShape::GetOverlayPriority() const // Set up maximum priority for shapes which created by user in the editor. if (m_params.m_createdByEditor) return dp::kPriorityMaskAll; - + // Set up minimal priority for shapes which belong to areas. if (m_params.m_hasArea) return 0; diff --git a/drape_frontend/shape_view_params.hpp b/drape_frontend/shape_view_params.hpp index 56c791bc6b..be8eea5fd8 100644 --- a/drape_frontend/shape_view_params.hpp +++ b/drape_frontend/shape_view_params.hpp @@ -29,7 +29,7 @@ struct PoiSymbolViewParams : CommonViewParams float m_posZ = 0.0f; bool m_hasArea = false; bool m_createdByEditor = false; - bool m_deletedInEditor = false; + bool m_obsoleteInEditor = false; }; struct CircleViewParams : CommonViewParams diff --git a/indexer/index.hpp b/indexer/index.hpp index 7e4fa77153..eb850cafd1 100644 --- a/indexer/index.hpp +++ b/indexer/index.hpp @@ -116,7 +116,9 @@ private: FeatureType feature; switch (m_editor.GetFeatureStatus(mwmID, index)) { - case osm::Editor::FeatureStatus::Deleted: return; + case osm::Editor::FeatureStatus::Deleted: + case osm::Editor::FeatureStatus::Obsolete: + return; case osm::Editor::FeatureStatus::Modified: VERIFY(m_editor.GetEditedFeature(mwmID, index, feature), ()); m_f(feature); diff --git a/indexer/osm_editor.cpp b/indexer/osm_editor.cpp index 9d7a9ee6f0..fa646a62b5 100644 --- a/indexer/osm_editor.cpp +++ b/indexer/osm_editor.cpp @@ -55,6 +55,7 @@ constexpr char const * kXmlMwmNode = "mwm"; constexpr char const * kDeleteSection = "delete"; constexpr char const * kModifySection = "modify"; constexpr char const * kCreateSection = "create"; +constexpr char const * kObsoleteSection = "obsolete"; /// We store edited streets in OSM-compatible way. constexpr char const * kAddrStreetTag = "addr:street"; @@ -165,13 +166,14 @@ void Editor::LoadMapEdits() } } - array, 3> const sections = + array, 4> const sections = {{ {FeatureStatus::Deleted, kDeleteSection}, {FeatureStatus::Modified, kModifySection}, + {FeatureStatus::Obsolete, kObsoleteSection}, {FeatureStatus::Created, kCreateSection} }}; - int deleted = 0, modified = 0, created = 0; + int deleted = 0, obsolete = 0, modified = 0, created = 0; bool needRewriteEdits = false; @@ -230,6 +232,7 @@ void Editor::LoadMapEdits() { case FeatureStatus::Deleted: ++deleted; break; case FeatureStatus::Modified: ++modified; break; + case FeatureStatus::Obsolete: ++obsolete; break; case FeatureStatus::Created: ++created; break; case FeatureStatus::Untouched: ASSERT(false, ()); continue; } @@ -253,7 +256,8 @@ void Editor::LoadMapEdits() // Save edits with new indexes and mwm version to avoid another migration on next startup. if (needRewriteEdits) Save(GetEditorFilePath()); - LOG(LINFO, ("Loaded", modified, "modified,", created, "created and", deleted, "deleted features.")); + LOG(LINFO, ("Loaded", modified, "modified,", + created, "created,", deleted, "deleted and", obsolete, "obsolete features.")); } bool Editor::Save(string const & fullFilePath) const @@ -280,6 +284,7 @@ bool Editor::Save(string const & fullFilePath) const xml_node deleted = mwmNode.append_child(kDeleteSection); xml_node modified = mwmNode.append_child(kModifySection); xml_node created = mwmNode.append_child(kCreateSection); + xml_node obsolete = mwmNode.append_child(kObsoleteSection); for (auto const & index : mwm.second) { FeatureTypeInfo const & fti = index.second; @@ -303,6 +308,7 @@ bool Editor::Save(string const & fullFilePath) const case FeatureStatus::Deleted: VERIFY(xf.AttachToParentNode(deleted), ()); break; case FeatureStatus::Modified: VERIFY(xf.AttachToParentNode(modified), ()); break; case FeatureStatus::Created: VERIFY(xf.AttachToParentNode(created), ()); break; + case FeatureStatus::Obsolete: VERIFY(xf.AttachToParentNode(obsolete), ()); break; case FeatureStatus::Untouched: CHECK(false, ("Not edited features shouldn't be here.")); } } @@ -404,6 +410,8 @@ Editor::SaveResult Editor::SaveEditedFeature(EditableMapObject const & emo) FeatureTypeInfo fti; auto const featureStatus = GetFeatureStatus(fid.m_mwmId, fid.m_index); + ASSERT_NOT_EQUAL(featureStatus, FeatureStatus::Obsolete, ("Obsolete feature cannot be modified")); + bool const wasCreatedByUser = IsCreatedFeature(fid); if (wasCreatedByUser && featureStatus == FeatureStatus::Untouched) { @@ -571,6 +579,9 @@ EditableProperties Editor::GetEditableProperties(FeatureType const & feature) co if (!version::IsSingleMwm(feature.GetID().m_mwmId.GetInfo()->m_version.GetVersion())) return {}; + if (GetFeatureStatus(feature.GetID()) == FeatureStatus::Obsolete) + return {}; + // TODO(mgsergio): Check if feature is in the area where editing is disabled in the config. auto editableProperties = GetEditablePropertiesForTypes(feature::TypesHolder(feature)); @@ -675,7 +686,7 @@ void Editor::UploadChanges(string const & key, string const & secret, TChangeset switch (fti.m_status) { case FeatureStatus::Untouched: CHECK(false, ("It's impossible.")); continue; - + case FeatureStatus::Obsolete: continue; // Obsolete features will be deleted by OSMers. case FeatureStatus::Created: { XMLFeature feature = fti.m_feature.ToXML(true); @@ -893,6 +904,23 @@ void Editor::Invalidate() m_invalidateFn(); } +void Editor::MarkFeatureAsObsolete(FeatureID const & fid) +{ + auto const featureStatus = GetFeatureStatus(fid); + ASSERT(featureStatus == FeatureStatus::Untouched || + featureStatus == FeatureStatus::Modified, + ("Created or deleted features can't be obsolete")); + + auto & fti = m_features[fid.m_mwmId][fid.m_index]; + // If a feature was modified we can drop all changes since it's now obsolete. + fti.m_feature = *m_getOriginalFeatureFn(fid); + fti.m_status = FeatureStatus::Obsolete; + fti.m_modificationTimestamp = time(nullptr); + + Save(GetEditorFilePath()); + Invalidate(); +} + Editor::Stats Editor::GetStats() const { Stats stats; @@ -966,6 +994,7 @@ void Editor::CreateNote(ms::LatLon const & latLon, FeatureID const & fid, sstr << kPlaceDoesNotExistMessage; if (!note.empty()) sstr << " User comments: \"" << note << '\"'; + MarkFeatureAsObsolete(fid); break; case NoteProblemType::General: sstr << note; @@ -988,6 +1017,7 @@ string DebugPrint(Editor::FeatureStatus fs) { case Editor::FeatureStatus::Untouched: return "Untouched"; case Editor::FeatureStatus::Deleted: return "Deleted"; + case Editor::FeatureStatus::Obsolete: return "Obsolete"; case Editor::FeatureStatus::Modified: return "Modified"; case Editor::FeatureStatus::Created: return "Created"; }; diff --git a/indexer/osm_editor.hpp b/indexer/osm_editor.hpp index 8098ea077d..e3d3070493 100644 --- a/indexer/osm_editor.hpp +++ b/indexer/osm_editor.hpp @@ -48,6 +48,7 @@ public: { Untouched, Deleted, + Obsolete, // The feature is obsolete when is marked for deletion via note. Modified, Created }; @@ -157,6 +158,9 @@ public: }; Stats GetStats() const; + // Don't use this function to determine if a feature in editor was created. + // Use GetFeatureStatus(fid) instead. This function is used when a feature is + // not yet saved and we have to know if it was modified or created. static bool IsCreatedFeature(FeatureID const & fid); private: @@ -167,6 +171,9 @@ private: /// Notify framework that something has changed and should be redisplayed. void Invalidate(); + // Saves a feature in internal storage with FeatureStatus::Obsolete status. + void MarkFeatureAsObsolete(FeatureID const & fid); + FeatureID GenerateNewFeatureId(MwmSet::MwmId const & id); EditableProperties GetEditablePropertiesForTypes(feature::TypesHolder const & types) const; diff --git a/iphone/Maps/Classes/Editor/MWMEditorViewController.mm b/iphone/Maps/Classes/Editor/MWMEditorViewController.mm index 415b73a0db..da9e2f5de4 100644 --- a/iphone/Maps/Classes/Editor/MWMEditorViewController.mm +++ b/iphone/Maps/Classes/Editor/MWMEditorViewController.mm @@ -670,6 +670,7 @@ void registerCellsForTableView(vector const & cells, UITab case osm::Editor::FeatureStatus::Untouched: return L(@"editor_place_doesnt_exist"); case osm::Editor::FeatureStatus::Deleted: + case osm::Editor::FeatureStatus::Obsolete: // TODO(Vlad): Either make a valid button or disable it. NSAssert(false, @"Incorrect feature status!"); return L(@"editor_place_doesnt_exist"); case osm::Editor::FeatureStatus::Modified: @@ -893,7 +894,7 @@ void registerCellsForTableView(vector const & cells, UITab - (void)tryToChangeInvalidStateForCell:(MWMEditorTextTableViewCell *)cell { [self.tableView beginUpdates]; - + NSIndexPath * indexPath = [self.tableView indexPathForCell:cell]; [self.invalidCells removeObject:indexPath]; diff --git a/search/mwm_context.cpp b/search/mwm_context.cpp index b89575d420..d9a066b127 100644 --- a/search/mwm_context.cpp +++ b/search/mwm_context.cpp @@ -21,7 +21,9 @@ bool MwmContext::GetFeature(uint32_t index, FeatureType & ft) const { switch (GetEditedStatus(index)) { - case osm::Editor::FeatureStatus::Deleted: return false; + case osm::Editor::FeatureStatus::Deleted: + case osm::Editor::FeatureStatus::Obsolete: + return false; case osm::Editor::FeatureStatus::Modified: case osm::Editor::FeatureStatus::Created: VERIFY(osm::Editor::Instance().GetEditedFeature(GetId(), index, ft), ());