Celestia

Форк
0
/
category.cpp 
290 строк · 7.9 Кб
1
#include "category.h"
2

3
#include <algorithm>
4
#include <initializer_list>
5
#include <utility>
6

7
#include <celutil/gettext.h>
8
#include "hash.h"
9
#include "value.h"
10

11
UserCategoryManager::UserCategoryManager() = default;
12
UserCategoryManager::~UserCategoryManager() = default;
13

14
UserCategoryId
15
UserCategoryManager::create(const std::string& name,
16
                            UserCategoryId parent,
17
                            const std::string& domain)
18
{
19
    if (parent != UserCategoryId::Invalid)
20
    {
21
        auto parentIndex = static_cast<std::size_t>(parent);
22
        if (parentIndex >= m_categories.size() || m_categories[parentIndex] == nullptr)
23
            return UserCategoryId::Invalid;
24
    }
25

26
    UserCategoryId id;
27
    bool reusedExisting = false;
28
    if (m_available.empty())
29
        id = static_cast<UserCategoryId>(m_categories.size());
30
    else
31
    {
32
        id = m_available.back();
33
        m_available.pop_back();
34
        reusedExisting = true;
35
    }
36

37
    if (!m_categoryMap.try_emplace(name, id).second)
38
    {
39
        if (reusedExisting)
40
            m_available.push_back(id);
41
        return UserCategoryId::Invalid;
42
    }
43

44
    return createNew(id, name, parent, domain);
45
}
46

47
bool
48
UserCategoryManager::destroy(UserCategoryId category)
49
{
50
    auto categoryIndex = static_cast<std::size_t>(category);
51
    if (categoryIndex >= m_categories.size() || m_categories[categoryIndex] == nullptr)
52
        return false;
53

54
    auto& entry = m_categories[categoryIndex];
55
    if (!entry->m_children.empty())
56
        return false;
57

58
    // remove all members
59
    for (const Selection& sel : entry->m_members)
60
    {
61
        auto it = m_objectMap.find(sel);
62
        if (it == m_objectMap.end())
63
            continue;
64

65
        auto& categories = it->second;
66
        if (auto item = std::find(categories.begin(), categories.end(), category); item != categories.end())
67
        {
68
            categories.erase(item);
69
            if (categories.empty())
70
                m_objectMap.erase(it);
71
        }
72
    }
73

74
    m_active.erase(category);
75
    if (entry->m_parent == UserCategoryId::Invalid)
76
        m_roots.erase(category);
77
    else
78
    {
79
        auto& parentChildren = m_categories[static_cast<std::size_t>(entry->m_parent)]->m_children;
80
        auto it = std::find(parentChildren.begin(), parentChildren.end(), category);
81
        parentChildren.erase(it);
82
    }
83

84
    m_categoryMap.erase(entry->m_name);
85
    m_categories[categoryIndex] = nullptr;
86
    m_available.push_back(category);
87

88
    entry.reset();
89
    return true;
90
}
91

92
const UserCategory*
93
UserCategoryManager::get(UserCategoryId category) const
94
{
95
    auto categoryIndex = static_cast<std::size_t>(category);
96
    if (categoryIndex >= m_categories.size())
97
        return nullptr;
98
    return m_categories[categoryIndex].get();
99
}
100

101
UserCategoryId
102
UserCategoryManager::find(std::string_view name) const
103
{
104
    auto it = m_categoryMap.find(name);
105
    return it == m_categoryMap.end()
106
        ? UserCategoryId::Invalid
107
        : it->second;
108
}
109

110
UserCategoryId
111
UserCategoryManager::findOrAdd(const std::string& name, const std::string& domain)
112
{
113
    auto id = static_cast<UserCategoryId>(m_categories.size());
114
    if (auto [it, emplaced] = m_categoryMap.try_emplace(name, id); !emplaced)
115
        return it->second;
116

117
    return createNew(id, name, UserCategoryId::Invalid, domain);
118
}
119

120
UserCategoryId
121
UserCategoryManager::createNew(UserCategoryId id,
122
                               const std::string& name,
123
                               UserCategoryId parent,
124
                               const std::string& domain)
125
{
126
#if ENABLE_NLS
127
    std::string i18nName = dgettext(name.c_str(), domain.c_str());
128
#else
129
    std::string i18nName = name;
130
#endif
131

132
    auto category = std::make_unique<UserCategory>(ConstructorToken{}, name, parent, std::move(i18nName));
133

134
    if (auto idIndex = static_cast<std::size_t>(id); idIndex < m_categories.size())
135
        m_categories[idIndex] = std::move(category);
136
    else
137
        m_categories.push_back(std::move(category));
138

139
    m_active.emplace(id);
140
    if (parent == UserCategoryId::Invalid)
141
        m_roots.emplace(id);
142
    else
143
        m_categories[static_cast<std::size_t>(parent)]->m_children.push_back(id);
144

145
    return id;
146
}
147

148
bool
149
UserCategoryManager::addObject(Selection selection, UserCategoryId category)
150
{
151
    auto categoryIndex = static_cast<std::size_t>(category);
152
    if (categoryIndex >= m_categories.size())
153
        return false;
154

155
    if (!m_categories[categoryIndex]->m_members.emplace(selection).second)
156
        return false;
157

158
    if (auto it = m_objectMap.find(selection); it == m_objectMap.end())
159
        m_objectMap.try_emplace(selection, std::initializer_list<UserCategoryId> { category });
160
    else
161
        it->second.push_back(category);
162
    return true;
163
}
164

165
bool
166
UserCategoryManager::removeObject(Selection selection, UserCategoryId category)
167
{
168
    auto categoryIndex = static_cast<std::size_t>(category);
169
    if (categoryIndex >= m_categories.size())
170
        return false;
171

172
    if (m_categories[categoryIndex]->m_members.erase(selection) == 0)
173
        return false;
174

175
    auto it = m_objectMap.find(selection);
176
    if (it == m_objectMap.end())
177
    {
178
        assert(false);
179
        return true;
180
    }
181

182
    auto& categories = it->second;
183
    if (auto item = std::find(categories.begin(), categories.end(), category); item != categories.end())
184
    {
185
        categories.erase(item);
186
        if (categories.empty())
187
            m_objectMap.erase(it);
188
    }
189

190
    return true;
191
}
192

193
void
194
UserCategoryManager::clearCategories(Selection selection)
195
{
196
    auto iter = m_objectMap.find(selection);
197
    if (iter == m_objectMap.end())
198
        return;
199

200
    for (UserCategoryId category : iter->second)
201
    {
202
        m_categories[static_cast<std::size_t>(category)]->m_members.erase(selection);
203
    }
204

205
    m_objectMap.erase(selection);
206
}
207

208
bool
209
UserCategoryManager::isInCategory(Selection selection, UserCategoryId category) const
210
{
211
    auto categoryIndex = static_cast<std::size_t>(category);
212
    if (categoryIndex >= m_categories.size())
213
        return false;
214

215
    const auto& members = m_categories[categoryIndex]->m_members;
216
    return members.find(selection) != members.end();
217
}
218

219
const std::vector<UserCategoryId>*
220
UserCategoryManager::getCategories(Selection selection) const
221
{
222
    auto it = m_objectMap.find(selection);
223
    return it == m_objectMap.end()
224
        ? nullptr
225
        : &it->second;
226
}
227

228
UserCategory::UserCategory(UserCategoryManager::ConstructorToken,
229
                           const std::string& name,
230
                           UserCategoryId parent,
231
                           std::string&& i18nName) :
232
    m_parent(parent),
233
    m_name(name),
234
    m_i18nName(std::move(i18nName))
235
{}
236

237
const std::string&
238
UserCategory::getName(bool i18n) const
239
{
240
    return i18n ? m_i18nName : m_name;
241
}
242

243
bool
244
UserCategory::hasChild(UserCategoryId child) const
245
{
246
    auto it = std::find(m_children.begin(), m_children.end(), child);
247
    return it != m_children.end();
248
}
249

250
const UserCategory*
251
UserCategory::get(UserCategoryId category)
252
{
253
    return manager.get(category);
254
}
255

256
void
257
UserCategory::loadCategories(Selection selection,
258
                             const AssociativeArray& hash,
259
                             DataDisposition disposition,
260
                             const std::string& domain)
261
{
262
    if (disposition == DataDisposition::Replace)
263
        manager.clearCategories(selection);
264

265
    auto categoryValue = hash.getValue("Category");
266
    if (categoryValue == nullptr)
267
        return;
268

269
    if (const std::string* cn = categoryValue->getString(); cn != nullptr)
270
    {
271
        if (cn->empty())
272
            return;
273
        auto categoryId = manager.findOrAdd(*cn, domain);
274
        manager.addObject(selection, categoryId);
275
    }
276

277
    const ValueArray *categoryArray = categoryValue->getArray();
278
    if (categoryArray == nullptr)
279
        return;
280

281
    for (const auto& it : *categoryArray)
282
    {
283
        const std::string* cn = it.getString();
284
        if (cn == nullptr || cn->empty())
285
            continue;
286

287
        auto categoryId = manager.findOrAdd(*cn, domain);
288
        manager.addObject(selection, categoryId);
289
    }
290
}
291

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.