Merge pull request #2882 from mgsergio/street-multilang-name

Street multilang name
This commit is contained in:
ygorshenin 2016-04-18 13:15:46 +03:00
commit 0abe598452
5 changed files with 112 additions and 54 deletions

View file

@ -322,15 +322,11 @@ Editor::FeatureStatus Editor::GetFeatureStatus(MwmSet::MwmId const & mwmId, uint
if (m_features.empty())
return FeatureStatus::Untouched;
auto const matchedMwm = m_features.find(mwmId);
if (matchedMwm == m_features.end())
auto const * featureInfo = GetFeatureTypeInfo(mwmId, index);
if (featureInfo == nullptr)
return FeatureStatus::Untouched;
auto const matchedIndex = matchedMwm->second.find(index);
if (matchedIndex == matchedMwm->second.end())
return FeatureStatus::Untouched;
return matchedIndex->second.m_status;
return featureInfo->m_status;
}
void Editor::DeleteFeature(FeatureType const & feature)
@ -503,32 +499,21 @@ void Editor::ForEachFeatureInMwmRectAndScale(MwmSet::MwmId const & id,
bool Editor::GetEditedFeature(MwmSet::MwmId const & mwmId, uint32_t index,
FeatureType & outFeature) const
{
auto const matchedMwm = m_features.find(mwmId);
if (matchedMwm == m_features.end())
auto const * featureInfo = GetFeatureTypeInfo(mwmId, index);
if (featureInfo == nullptr)
return false;
auto const matchedIndex = matchedMwm->second.find(index);
if (matchedIndex == matchedMwm->second.end())
return false;
// TODO(AlexZ): Should we process deleted/created features as well?
outFeature = matchedIndex->second.m_feature;
outFeature = featureInfo->m_feature;
return true;
}
bool Editor::GetEditedFeatureStreet(FeatureID const & fid, string & outFeatureStreet) const
{
// TODO(AlexZ): Reuse common code or better make better getters/setters for edited features.
auto const matchedMwm = m_features.find(fid.m_mwmId);
if (matchedMwm == m_features.end())
auto const * featureInfo = GetFeatureTypeInfo(fid.m_mwmId, fid.m_index);
if (featureInfo == nullptr)
return false;
auto const matchedIndex = matchedMwm->second.find(fid.m_index);
if (matchedIndex == matchedMwm->second.end())
return false;
// TODO(AlexZ): Should we process deleted/created features as well?
outFeatureStreet = matchedIndex->second.m_street;
outFeatureStreet = featureInfo->m_street;
return true;
}
@ -806,6 +791,36 @@ void Editor::SaveUploadedInformation(FeatureTypeInfo const & fromUploader)
Save(GetEditorFilePath());
}
// Macros is used to avoid code duplication.
#define GET_FEATURE_TYPE_INFO_BODY \
do \
{ \
/* TODO(mgsergio): machedMwm should be synchronized. */ \
auto const matchedMwm = m_features.find(mwmId); \
if (matchedMwm == m_features.end()) \
return nullptr; \
\
auto const matchedIndex = matchedMwm->second.find(index); \
if (matchedIndex == matchedMwm->second.end()) \
return nullptr; \
\
/* TODO(AlexZ): Should we process deleted/created features as well?*/ \
return &matchedIndex->second; \
} while (false)
Editor::FeatureTypeInfo const * Editor::GetFeatureTypeInfo(MwmSet::MwmId const & mwmId,
uint32_t index) const
{
GET_FEATURE_TYPE_INFO_BODY;
}
Editor::FeatureTypeInfo * Editor::GetFeatureTypeInfo(MwmSet::MwmId const & mwmId, uint32_t index)
{
GET_FEATURE_TYPE_INFO_BODY;
}
#undef GET_FEATURE_TYPE_INFO_BODY
void Editor::RemoveFeatureFromStorageIfExists(MwmSet::MwmId const & mwmId, uint32_t index)
{
auto matchedMwm = m_features.find(mwmId);

View file

@ -154,6 +154,9 @@ private:
string m_uploadStatus;
string m_uploadError;
};
/// @returns pointer to m_features[id][index] if exists, nullptr otherwise.
FeatureTypeInfo const * GetFeatureTypeInfo(MwmSet::MwmId const & mwmId, uint32_t index) const;
FeatureTypeInfo * GetFeatureTypeInfo(MwmSet::MwmId const & mwmId, uint32_t index);
void SaveUploadedInformation(FeatureTypeInfo const & fromUploader);
// TODO(AlexZ): Synchronize multithread access.

View file

@ -2452,26 +2452,38 @@ bool Framework::ParseEditorDebugCommand(search::SearchParams const & params)
namespace
{
vector<osm::LocalizedStreet> FilterNearbyStreets(vector<search::ReverseGeocoder::Street> const & streets,
string const & exactFeatureStreet = "")
osm::LocalizedStreet LocalizeStreet(Index const & index, FeatureID const & fid)
{
osm::LocalizedStreet result;
Index::FeaturesLoaderGuard g(index, fid.m_mwmId);
FeatureType ft;
g.GetFeatureByIndex(fid.m_index, ft);
ft.GetPreferredNames(result.m_defaultName, result.m_localizedName);
return result;
}
vector<osm::LocalizedStreet> TakeSomeStreetsAndLocalize(
vector<search::ReverseGeocoder::Street> const & streets, Index const & index)
{
vector<osm::LocalizedStreet> results;
// Exact feature street always goes first in Editor UI street list.
// TODO: Push into result LocalizedStreet object with default and localized street name.
if (!exactFeatureStreet.empty())
results.push_back({exactFeatureStreet, ""});
// Reasonable number of different nearby street names to display in UI.
constexpr size_t kMaxNumberOfNearbyStreetsToDisplay = 8;
for (auto const & street : streets)
{
osm::LocalizedStreet const st{street.m_name, ""};
if (find(results.begin(), results.end(), st) == results.end())
{
results.push_back(st);
if (results.size() >= kMaxNumberOfNearbyStreetsToDisplay)
break;
}
auto const isDuplicate = find_if(begin(results), end(results),
[&street](osm::LocalizedStreet const & s)
{
return s.m_defaultName == street.m_name;
}) != results.end();
if (isDuplicate)
continue;
results.push_back(LocalizeStreet(index, street.m_id));
if (results.size() >= kMaxNumberOfNearbyStreetsToDisplay)
break;
}
return results;
}
@ -2488,8 +2500,9 @@ bool Framework::CreateMapObject(m2::PointD const & mercator, uint32_t const feat
search::ReverseGeocoder const coder(m_model.GetIndex());
vector<search::ReverseGeocoder::Street> streets;
coder.GetNearbyStreets(mwmId, mercator, streets);
emo.SetNearbyStreets(FilterNearbyStreets(streets));
emo.SetNearbyStreets(TakeSomeStreetsAndLocalize(streets, m_model.GetIndex()));
return osm::Editor::Instance().CreatePoint(featureType, mercator, mwmId, emo);
}
@ -2505,31 +2518,56 @@ bool Framework::GetEditableMapObject(FeatureID const & fid, osm::EditableMapObje
osm::Editor & editor = osm::Editor::Instance();
emo.SetEditableProperties(editor.GetEditableProperties(ft));
// Get exact feature's street address (if any) from mwm,
// together with all nearby streets.
search::ReverseGeocoder const coder(m_model.GetIndex());
auto const streets = coder.GetNearbyFeatureStreets(ft);
auto const & streetsPool = streets.first;
auto const & featureStreetIndex = streets.second;
string street;
if (editor.GetEditedFeatureStreet(fid, street))
bool const featureIsInEditor = editor.GetEditedFeatureStreet(fid, street);
bool const featureHasStreetInMwm = featureStreetIndex < streetsPool.size();
if (!featureIsInEditor && featureHasStreetInMwm)
street = streetsPool[featureStreetIndex].m_name;
auto localizedStreets = TakeSomeStreetsAndLocalize(streetsPool, m_model.GetIndex());
if (!street.empty())
{
// Exact feature's street is taken directy from the Editor.
// Fill only nearby streets.
search::ReverseGeocoder const coder(m_model.GetIndex());
vector<search::ReverseGeocoder::Street> streets;
coder.GetNearbyStreets(fid.m_mwmId, feature::GetCenter(*feature), streets);
emo.SetNearbyStreets(FilterNearbyStreets(streets, street));
auto it = find_if(begin(streetsPool), end(streetsPool),
[&street](search::ReverseGeocoder::Street const & s)
{
return s.m_name == street;
});
if (it != end(streetsPool))
{
auto const localizedStreet = LocalizeStreet(m_model.GetIndex(), it->m_id);
emo.SetStreet(localizedStreet);
// A street that a feature belongs to should alwas be in the first place in the list.
auto localizedIt = find(begin(localizedStreets), end(localizedStreets), localizedStreet);
if (localizedIt != end(localizedStreets))
iter_swap(localizedIt, begin(localizedStreets));
else
localizedStreets.insert(begin(localizedStreets), localizedStreet);
}
else
{
emo.SetStreet({street, ""});
}
}
else
{
// Get exact feature's street address (if any) from mwm, together with all nearby streets.
search::ReverseGeocoder const coder(m_model.GetIndex());
auto const streets = coder.GetNearbyFeatureStreets(ft);
if (streets.second < streets.first.size())
street = streets.first[streets.second].m_name;
emo.SetNearbyStreets(FilterNearbyStreets(streets.first, street));
emo.SetStreet({});
}
//TODO: We have to set default and localized name if last one exists.
emo.SetStreet({street, ""});
emo.SetNearbyStreets(move(localizedStreets));
return true;
}
osm::Editor::SaveResult Framework::SaveEditedMapObject(osm::EditableMapObject const & emo)
{
if (!m_lastTapEvent)

View file

@ -87,6 +87,7 @@ EditorDialog::EditorDialog(QWidget * parent, osm::EditableMapObject & emo)
nearbyStreets.insert(nearbyStreets.begin(), {});
grid->addWidget(new QLabel(kStreetObjectName), row, 0);
QComboBox * cmb = new QComboBox();
cmb->setEditable(true);
for (int i = 0; i < nearbyStreets.size(); ++i)
{
string street = nearbyStreets[i].m_defaultName;

View file

@ -82,7 +82,8 @@ public:
void GetNearbyStreets(FeatureType & ft, vector<Street> & streets) const;
//@}
/// @returns [a lot of] nearby feature's streets and feature's street index, if valid ( < vector.size()).
/// @returns [a lot of] nearby feature's streets and an index of a feature's street.
/// Returns a value greater than vector size when there are no Street the feature belongs to.
/// @note returned vector can contain duplicated street segments.
pair<vector<Street>, uint32_t> GetNearbyFeatureStreets(FeatureType & ft) const;