1 /*
2 * This file is part of Poedit (http://poedit.net)
3 *
4 * Copyright (C) 1999-2015 Vaclav Slavik
5 * Copyright (C) 2005 Olivier Sannier
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27 #include "cat_sorting.h"
28
29 #include <unicode/unistr.h>
30 #include "str_helpers.h"
31
32 #include <wx/config.h>
33 #include <wx/log.h>
34
Default()35 /*static*/ SortOrder SortOrder::Default()
36 {
37 SortOrder order;
38
39 wxString by = wxConfig::Get()->Read("/sort_by", "file-order");
40 long ctxt = wxConfig::Get()->Read("/sort_group_by_context", 0L);
41 long untrans = wxConfig::Get()->Read("/sort_untrans_first", 0L);
42 long errors = wxConfig::Get()->Read("/sort_errors_first", 1L);
43
44 if ( by == "source" )
45 order.by = By_Source;
46 else if ( by == "translation" )
47 order.by = By_Translation;
48 else
49 order.by = By_FileOrder;
50
51 order.groupByContext = (ctxt != 0);
52 order.untransFirst = (untrans != 0);
53 order.errorsFirst = (errors != 0);
54
55 return order;
56 }
57
58
Save()59 void SortOrder::Save()
60 {
61 wxString bystr;
62 switch ( by )
63 {
64 case By_FileOrder:
65 bystr = "file-order";
66 break;
67 case By_Source:
68 bystr = "source";
69 break;
70 case By_Translation:
71 bystr = "translation";
72 break;
73 }
74
75 wxConfig::Get()->Write("/sort_by", bystr);
76 wxConfig::Get()->Write("/sort_group_by_context", groupByContext);
77 wxConfig::Get()->Write("/sort_untrans_first", untransFirst);
78 wxConfig::Get()->Write("/sort_errors_first", errorsFirst);
79 }
80
81
CatalogItemsComparator(const Catalog & catalog,const SortOrder & order)82 CatalogItemsComparator::CatalogItemsComparator(const Catalog& catalog, const SortOrder& order)
83 : m_catalog(catalog), m_order(order)
84 {
85 UErrorCode err = U_ZERO_ERROR;
86 switch (m_order.by)
87 {
88 case SortOrder::By_Source:
89 // TODO: allow non-English source languages too
90 m_collator.reset(icu::Collator::createInstance(catalog.GetSourceLanguage().ToIcu(), err));
91 break;
92
93 case SortOrder::By_Translation:
94 m_collator.reset(icu::Collator::createInstance(catalog.GetLanguage().ToIcu(), err));
95 break;
96
97 case SortOrder::By_FileOrder:
98 break;
99 }
100
101 if (!U_SUCCESS(err) || err == U_USING_FALLBACK_WARNING)
102 {
103 wxLogTrace("poedit", "warning: not using collation for %s (%s)",
104 catalog.GetLanguage().Code(), u_errorName(err));
105 }
106
107 if (m_collator)
108 {
109 // Case-insensitive comparison:
110 m_collator->setStrength(icu::Collator::SECONDARY);
111 }
112 }
113
114
operator ()(int i,int j) const115 bool CatalogItemsComparator::operator()(int i, int j) const
116 {
117 const CatalogItem& a = Item(i);
118 const CatalogItem& b = Item(j);
119
120 if ( m_order.errorsFirst )
121 {
122 if ( a.GetValidity() == CatalogItem::Val_Invalid && b.GetValidity() != CatalogItem::Val_Invalid )
123 return true;
124 else if ( a.GetValidity() != CatalogItem::Val_Invalid && b.GetValidity() == CatalogItem::Val_Invalid )
125 return false;
126 }
127
128 if ( m_order.untransFirst )
129 {
130 if ( !a.IsTranslated() && b.IsTranslated() )
131 return true;
132 else if ( a.IsTranslated() && !b.IsTranslated() )
133 return false;
134
135 if ( a.IsFuzzy() && !b.IsFuzzy() )
136 return true;
137 else if ( !a.IsFuzzy() && b.IsFuzzy() )
138 return false;
139 }
140
141 if ( m_order.groupByContext )
142 {
143 if ( a.HasContext() && !b.HasContext() )
144 return true;
145 else if ( !a.HasContext() && b.HasContext() )
146 return false;
147 else if ( a.HasContext() && b.HasContext() )
148 {
149 int r = CompareStrings(a.GetContext(), b.GetContext());
150 if ( r != 0 )
151 return r < 0;
152 }
153 }
154
155 switch ( m_order.by )
156 {
157 case SortOrder::By_FileOrder:
158 {
159 return i < j;
160 }
161
162 case SortOrder::By_Source:
163 {
164 int r = CompareStrings(a.GetString(), b.GetString());
165 if ( r != 0 )
166 return r < 0;
167 break;
168 }
169
170 case SortOrder::By_Translation:
171 {
172 int r = CompareStrings(a.GetTranslation(), b.GetTranslation());
173 if ( r != 0 )
174 return r < 0;
175 break;
176 }
177 }
178
179 // As last resort, sort by position in file. Note that this means that
180 // no two items are considered equal w.r.t. sort order; this ensures stable
181 // ordering.
182 return i < j;
183 }
184
185
CompareStrings(wxString a,wxString b) const186 int CatalogItemsComparator::CompareStrings(wxString a, wxString b) const
187 {
188 a.Replace("&", "");
189 a.Replace("_", "");
190
191 b.Replace("&", "");
192 b.Replace("_", "");
193
194 if (m_collator)
195 {
196 UErrorCode err = U_ZERO_ERROR;
197 #if wxUSE_UNICODE_UTF8
198 return m_collator->compareUTF8(a.wx_str(), b.wx_str(), err);
199 #elif SIZEOF_WCHAR_T == 2
200 return m_collator->compare(a.wx_str(), a.length(), b.wx_str(), b.length(), err);
201 #else
202 return m_collator->compare(str::to_icu(a), str::to_icu(b), err);
203 #endif
204 }
205 else
206 {
207 return a.CmpNoCase(b);
208 }
209 }
210