--- /dev/null
+/*
+ * Copyright (c) 2015-2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef I18N_COLLATOR_H
+#define I18N_COLLATOR_H
+
+#include "I18n/UniString.h"
+#include <utils_i18n_ucollator.h>
+
+namespace I18n
+{
+ /**
+ * @brief Provides locale-dependent string comparison.
+ */
+ class EXPORT_API Collator
+ {
+ public:
+ /**
+ * @brief Create collator.
+ * @param[in] strength Collation strength
+ * @see i18n_ucollator_strength_e
+ */
+ explicit Collator(i18n_ucollator_strength_e strength = I18N_UCOLLATOR_PRIMARY);
+ Collator(const Collator &that) = delete;
+ Collator(Collator &&that);
+ ~Collator();
+
+ Collator &operator=(const Collator &that) = delete;
+ Collator &operator=(Collator &&that);
+
+ /**
+ * @brief Initialize the collator with current locale.
+ * @remark Can be called several times.
+ */
+ void initialize();
+
+ /**
+ * @brief Compare two strings.
+ * @pre Should be initialized by calling initialize().
+ * @param[in] str1 First string
+ * @param[in] str2 Second string
+ * @return 0 if equal, -1 if str1 < str2, otherwise 1.
+ */
+ int compare(const UniString &str1, const UniString &str2);
+
+ private:
+ i18n_ucollator_strength_e m_Strength;
+ i18n_ucollator_h m_Handle;
+ };
+}
+
+#endif /* I18N_COLLATOR_H */
--- /dev/null
+/*
+ * Copyright (c) 2015-2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "I18n/Collator.h"
+#include <system_settings.h>
+
+using namespace I18n;
+
+Collator::Collator(i18n_ucollator_strength_e strength)
+ : m_Strength(strength), m_Handle(nullptr)
+{
+}
+
+Collator::Collator(Collator &&that)
+ : m_Strength(that.m_Strength), m_Handle(that.m_Handle)
+{
+ that.m_Handle = nullptr;
+}
+
+Collator::~Collator()
+{
+ i18n_ucollator_destroy(m_Handle);
+}
+
+Collator &Collator::operator=(Collator &&that)
+{
+ i18n_ucollator_destroy(m_Handle);
+ m_Strength = that.m_Strength;
+ m_Handle = that.m_Handle;
+ that.m_Handle = nullptr;
+ return *this;
+}
+
+void Collator::initialize()
+{
+ if (m_Handle) {
+ i18n_ucollator_destroy(m_Handle);
+ m_Handle = nullptr;
+ }
+
+ char *lang = nullptr;
+ system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &lang);
+ i18n_ucollator_create(lang, &m_Handle);
+ i18n_ucollator_set_strength(m_Handle, m_Strength);
+ free(lang);
+}
+
+int Collator::compare(const UniString& str1, const UniString &str2)
+{
+ int result = 0;
+ i18n_ucollator_str_collator(m_Handle,
+ str1.getI18nStr().c_str(), -1,
+ str2.getI18nStr().c_str(), -1,
+ (i18n_ucollator_result_e *) &result);
+ return result;
+}
#include "Common/DataTypes.h"
#include "Model2/SearchProvider.h"
#include "Ux/SelectView.h"
+#include "I18n/Collator.h"
#include "I18n/UniString.h"
-#include <map>
-
namespace Ui
{
class Genlist;
PersonItem *getNextPersonItem(PersonGroupItem *group, const Model::Person &person);
void linkPersonItems(PersonItem *sectionItem);
+ void onLanguageChanged(Evas_Object *obj, void *eventInfo);
void onIndexUpdated();
void onPersonInserted(::Model2::DataItem &data);
void onSectionUpdated(ContactItem *item, ::Model2::ChangeType change, SectionId sectionId);
std::vector<State> m_StateHistory;
Section m_Sections[SectionMax];
- std::map<I18n::UniString, PersonGroupItem *> m_PersonGroups;
+ std::vector<PersonGroupItem *> m_PersonGroups;
Model2::DataProvider *m_PersonProvider;
Model2::SearchProvider *m_SearchProvider;
+ I18n::Collator m_Collator;
FillCallback m_OnFilled;
};
}
const I18n::UniString &getIndexLetter() const;
/**
- * @brief Compares person's "Sort by" (first name/last name) values
- * @return True if sort value less than in @a that, otherwise false
+ * @return "Sort by" (first name/last name) value.
*/
- bool operator<(const Person &that) const;
+ const I18n::UniString &getSortValue() const;
/**
* @brief Add contact to person
contacts_record_h getContactChildRecord(unsigned propertyId, Pred predicate) const;
const ContactChildRecords getContactChildRecords(unsigned propertyId) const;
- const I18n::UniString &getSortValue() const;
virtual int onUpdate(void *data) override;
int updateName(contacts_record_h record, unsigned sortProperty);
void updateDefaultContactRecord();
#include "Ui/Window.h"
#include "Utils/Callback.h"
#include "Utils/Logger.h"
+#include "Utils/Range.h"
#include "Utils/Thread.h"
#include "ListPath.h"
void ListView::onInitialized()
{
+ m_Collator.initialize();
+
fillPersonList();
updateIndexFirstItem();
updateSections();
}
}
- return !m_PersonGroups.empty() ? m_PersonGroups.begin()->second : nullptr;
+ return !m_PersonGroups.empty() ? m_PersonGroups.front(): nullptr;
}
bool ListView::getSectionVisibility(SectionId sectionId)
void ListView::fillLayout()
{
Evas_Object *box = getEvasObject();
+ evas_object_smart_callback_add(box, "language,changed",
+ makeCallback(&ListView::onLanguageChanged), this);
m_ListLayout = createListLayout(box);
elm_box_pack_end(box, m_ListLayout);
void ListView::updateIndexFirstItem()
{
if (!m_PersonGroups.empty()) {
- m_Index->setFirstIndexedItem(m_PersonGroups.begin()->second);
+ m_Index->setFirstIndexedItem(m_PersonGroups.front());
} else {
m_Index->setFirstIndexedItem(nullptr);
}
PersonGroupItem *ListView::getPersonGroupItem(const UniString &indexLetter)
{
- auto insertResult = m_PersonGroups.insert({ indexLetter, nullptr });
- auto groupIt = insertResult.first;
+ auto it = std::lower_bound(m_PersonGroups.begin(), m_PersonGroups.end(), indexLetter,
+ [this](const PersonGroupItem *groupItem, const UniString &letter) {
+ return m_Collator.compare(groupItem->getTitle(), letter) < 0;
+ });
- /* Whether insert was successful (i.e. there is no such group yet) */
- if (insertResult.second) {
- PersonGroupItem *nextGroupItem = nullptr;
- auto nextGroupIt = Utils::advance(groupIt, 1);
- if (nextGroupIt != m_PersonGroups.end()) {
- nextGroupItem = nextGroupIt->second;
+ PersonGroupItem *nextGroupItem = nullptr;
+ if (it != m_PersonGroups.end()) {
+ if ((*it)->getTitle() == indexLetter) {
+ return *it;
+ } else {
+ nextGroupItem = *it;
}
-
- groupIt->second = insertPersonGroupItem(indexLetter, nextGroupItem);
}
- return groupIt->second;
+ PersonGroupItem *groupItem = insertPersonGroupItem(indexLetter, nextGroupItem);
+ m_PersonGroups.insert(it, groupItem);
+ return groupItem;
}
PersonGroupItem *ListView::insertPersonGroupItem(const UniString &indexLetter,
void ListView::deletePersonGroupItem(PersonGroupItem *group)
{
- m_PersonGroups.erase(group->getTitle());
+ auto it = std::find(m_PersonGroups.begin(), m_PersonGroups.end(), group);
+ m_PersonGroups.erase(it);
m_Index->removeIndexedItem(group);
updateIndexFirstItem();
delete group;
{
for (auto &&item : *group) {
auto personItem = static_cast<PersonItem *>(item);
- if (person < personItem->getPerson()) {
+ if (m_Collator.compare(person.getSortValue(), personItem->getPerson().getSortValue()) < 0) {
return personItem;
}
}
void ListView::linkPersonItems(PersonItem *sectionItem)
{
for (auto &&group : m_PersonGroups) {
- for (auto &&item : *group.second) {
+ for (auto &&item : *group) {
auto personItem = static_cast<PersonItem *>(item);
if (sectionItem->getPerson().getId() == personItem->getPerson().getId()) {
sectionItem->setExcluded(true);
}
}
+void ListView::onLanguageChanged(Evas_Object *obj, void *eventInfo)
+{
+ m_Collator.initialize();
+ std::sort(m_PersonGroups.begin(), m_PersonGroups.end(),
+ [this](const PersonGroupItem *group1, const PersonGroupItem *group2) {
+ return m_Collator.compare(group1->getTitle(), group2->getTitle()) < 0;
+ });
+
+ PersonGroupItem *nextGroupItem = nullptr;
+ for (auto &&groupItem : makeRange(m_PersonGroups.rbegin(), m_PersonGroups.rend())) {
+ if (groupItem->getNextGroupItem() != nextGroupItem) {
+ m_Genlist->insert(groupItem, nullptr, nextGroupItem);
+ }
+ nextGroupItem = groupItem;
+ }
+}
+
void ListView::onIndexUpdated()
{
Ui::GenGroupItem *sectionItem = m_Sections[SectionFavorites].m_Item;
if (sectionItem && sectionItem->isInserted()) {
m_Index->addIndexedItem(sectionItem, SYMBOL_STAR);
}
- for (auto &&pair : m_PersonGroups) {
- PersonGroupItem *groupItem = pair.second;
+ for (auto &&groupItem : m_PersonGroups) {
m_Index->addIndexedItem(groupItem, groupItem->getTitle().getUtf8Str().c_str());
}
}
return m_IndexLetter;
}
-bool Person::operator<(const Person &that) const
+const UniString &Person::getSortValue() const
{
- return getSortValue() < that.getSortValue();
+ if (m_SortValue.getI18nStr().empty()) {
+ contacts_record_h nameRecord = getChildRecord(m_DefaultContactRecord, _contacts_contact.name);
+ const char *value = getRecordStr(nameRecord, m_SortProperty);
+ m_SortValue = (value && *value) ? value : getName();
+ }
+
+ return m_SortValue;
}
void Person::addContact(contacts_record_h record)
return records;
}
-const UniString &Person::getSortValue() const
-{
- if (m_SortValue.getI18nStr().empty()) {
- contacts_record_h nameRecord = getChildRecord(m_DefaultContactRecord, _contacts_contact.name);
- const char *value = getRecordStr(nameRecord, m_SortProperty);
- m_SortValue = (value && *value) ? value : getName();
- }
-
- return m_SortValue;
-}
-
int Person::onUpdate(void *data)
{
contacts_record_h personRecord = (contacts_record_h) data;