PageRenderTime 49ms CodeModel.GetById 12ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llresmgr.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 352 lines | 230 code | 46 blank | 76 comment | 38 complexity | 36bba6e2c560c1c38d9a50db093c8135 MD5 | raw file
  1/** 
  2 * @file llresmgr.cpp
  3 * @brief Localized resource manager
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27// NOTE: this is a MINIMAL implementation.  The interface will remain, but the implementation will
 28// (when the time is right) become dynamic and probably use external files.
 29
 30#include "linden_common.h"
 31
 32#include "llresmgr.h"
 33#include "llfontgl.h"
 34#include "llerror.h"
 35#include "llstring.h"
 36
 37
 38LLResMgr::LLResMgr()
 39{
 40	// Set default
 41	setLocale( LLLOCALE_USA );
 42}
 43
 44
 45void LLResMgr::setLocale( LLLOCALE_ID locale_id )
 46{
 47	mLocale = locale_id;
 48
 49	//RN: for now, use normal 'C' locale for everything but specific UI input/output routines
 50//	switch( locale_id )
 51//	{
 52//	case LLLOCALE_USA: 
 53//#if LL_WINDOWS
 54//		// Windows doesn't use ISO country codes.
 55//		llinfos << "Setting locale to " << setlocale( LC_ALL, "english-usa" ) << llendl;
 56//#else	
 57//		// posix version should work everywhere else.
 58//		llinfos << "Setting locale to " << setlocale( LC_ALL, "en_US" ) << llendl;
 59//#endif
 60//		break;
 61//	case LLLOCALE_UK:
 62//#if LL_WINDOWS
 63//		// Windows doesn't use ISO country codes.
 64//		llinfos << "Setting locale to " << setlocale( LC_ALL, "english-uk" ) << llendl;
 65//#else
 66//		// posix version should work everywhere else.
 67//		llinfos << "Setting locale to " << setlocale( LC_ALL, "en_GB" ) << llendl;
 68//#endif
 69//		break;
 70//	default:
 71//		llassert(0);
 72//		setLocale(LLLOCALE_USA);
 73//		break;
 74//	}
 75}
 76
 77char LLResMgr::getDecimalPoint() const					
 78{ 
 79	char decimal = localeconv()->decimal_point[0]; 
 80
 81#if LL_DARWIN
 82	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
 83	if(decimal == 0)
 84	{
 85		decimal = '.';
 86	}
 87#endif
 88
 89	return decimal;
 90}
 91
 92char LLResMgr::getThousandsSeparator() const			
 93{
 94	char separator = localeconv()->thousands_sep[0]; 
 95
 96#if LL_DARWIN
 97	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
 98	if(separator == 0)
 99	{
100		separator = ',';
101	}
102#endif
103
104	return separator;
105}
106
107char LLResMgr::getMonetaryDecimalPoint() const
108{
109	char decimal = localeconv()->mon_decimal_point[0]; 
110
111#if LL_DARWIN
112	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
113	if(decimal == 0)
114	{
115		decimal = '.';
116	}
117#endif
118
119	return decimal;
120}
121
122char LLResMgr::getMonetaryThousandsSeparator() const	
123{
124	char separator = localeconv()->mon_thousands_sep[0]; 
125
126#if LL_DARWIN
127	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
128	if(separator == 0)
129	{
130		separator = ',';
131	}
132#endif
133
134	return separator;
135}
136
137
138// Sets output to a string of integers with monetary separators inserted according to the locale.
139std::string LLResMgr::getMonetaryString( S32 input ) const
140{
141	std::string output;
142
143	LLLocale locale(LLLocale::USER_LOCALE);
144	struct lconv *conv = localeconv();
145	
146#if LL_DARWIN
147	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
148	// Fake up a conv structure with some reasonable values for the fields this function uses.
149	struct lconv fakeconv;
150	char fake_neg[2] = "-";
151	char fake_mon_group[4] = "\x03\x03\x00"; // commas every 3 digits
152	if(conv->negative_sign[0] == 0)	// Real locales all seem to have something here...
153	{
154		fakeconv = *conv;	// start with what's there.
155		switch(mLocale)
156		{
157			default:  			// Unknown -- use the US defaults.
158			case LLLOCALE_USA: 
159			case LLLOCALE_UK:	// UK ends up being the same as US for the items used here.
160				fakeconv.negative_sign = fake_neg;
161				fakeconv.mon_grouping = fake_mon_group;
162				fakeconv.n_sign_posn = 1; // negative sign before the string
163			break;
164		}
165		conv = &fakeconv;
166	}
167#endif
168
169	char* negative_sign = conv->negative_sign;
170	char separator = getMonetaryThousandsSeparator();
171	char* grouping = conv->mon_grouping;
172	
173	// Note on mon_grouping:
174	// Specifies a string that defines the size of each group of digits in formatted monetary quantities.
175	// The operand for the mon_grouping keyword consists of a sequence of semicolon-separated integers. 
176	// Each integer specifies the number of digits in a group. The initial integer defines the size of
177	// the group immediately to the left of the decimal delimiter. The following integers define succeeding
178	// groups to the left of the previous group. If the last integer is not -1, the size of the previous
179	// group (if any) is repeatedly used for the remainder of the digits. If the last integer is -1, no
180	// further grouping is performed. 
181
182
183	// Note: we assume here that the currency symbol goes on the left. (Hey, it's Lindens! We can just decide.)
184	BOOL negative = (input < 0 );
185	BOOL negative_before = negative && (conv->n_sign_posn != 2);
186	BOOL negative_after = negative && (conv->n_sign_posn == 2);
187
188	std::string digits = llformat("%u", abs(input));
189	if( !grouping || !grouping[0] )
190	{
191		if( negative_before )
192		{
193			output.append( negative_sign );
194		}
195		output.append( digits );
196		if( negative_after )
197		{
198			output.append( negative_sign );
199		}
200		return output;
201	}
202
203	S32 groupings[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
204	S32 cur_group;
205	for( cur_group = 0; grouping[ cur_group ]; cur_group++ )
206	{
207		if( grouping[ cur_group ] != ';' )
208		{
209			groupings[cur_group] = grouping[ cur_group ];
210		}
211		cur_group++;
212
213		if( groupings[cur_group] < 0 )
214		{
215			break;
216		}
217	}
218	S32 group_count = cur_group;
219
220	char reversed_output[20] = "";	/* Flawfinder: ignore */
221	char forward_output[20] = "";	/* Flawfinder: ignore */
222	S32 output_pos = 0;
223	
224	cur_group = 0;
225	S32 pos = digits.size()-1;
226	S32 count_within_group = 0;
227	while( (pos >= 0) && (groupings[cur_group] >= 0) )
228	{
229		count_within_group++;
230		if( count_within_group > groupings[cur_group] )
231		{
232			count_within_group = 1;
233			reversed_output[ output_pos++ ] = separator;
234
235			if( (cur_group + 1) >= group_count )
236			{
237				break;
238			}
239			else
240			if( groupings[cur_group + 1] > 0 )
241			{
242				cur_group++;
243			}
244		}
245		reversed_output[ output_pos++ ] = digits[pos--];
246	}
247
248	while( pos >= 0 )
249	{
250		reversed_output[ output_pos++ ] = digits[pos--];
251	}
252
253
254	reversed_output[ output_pos ] = '\0';
255	forward_output[ output_pos ] = '\0';
256
257	for( S32 i = 0; i < output_pos; i++ )
258	{
259		forward_output[ output_pos - 1 - i ] = reversed_output[ i ];
260	}
261
262	if( negative_before )
263	{
264		output.append( negative_sign );
265	}
266	output.append( forward_output );
267	if( negative_after )
268	{
269		output.append( negative_sign );
270	}
271	return output;
272}
273
274void LLResMgr::getIntegerString( std::string& output, S32 input ) const
275{
276	// handle special case of input value being zero
277	if (input == 0)
278	{
279		output = "0";
280		return;
281	}
282	
283	// *NOTE: this method does not handle negative input integers correctly
284	S32 fraction = 0;
285	std::string fraction_string;
286	S32 remaining_count = input;
287	while(remaining_count > 0)
288	{
289		fraction = (remaining_count) % 1000;
290		
291		if (!output.empty())
292		{
293			if (fraction == remaining_count)
294			{
295				fraction_string = llformat_to_utf8("%d%c", fraction, getThousandsSeparator());
296			}
297			else
298			{
299				fraction_string = llformat_to_utf8("%3.3d%c", fraction, getThousandsSeparator());
300			}
301			output = fraction_string + output;
302		}
303		else
304		{
305			if (fraction == remaining_count)
306			{
307				fraction_string = llformat("%d", fraction);
308			}
309			else
310			{
311				fraction_string = llformat("%3.3d", fraction);
312			}
313			output = fraction_string;
314		}
315		remaining_count /= 1000;
316	}
317}
318
319#if LL_WINDOWS
320const std::string LLLocale::USER_LOCALE("English_United States.1252");// = LLStringUtil::null;
321const std::string LLLocale::SYSTEM_LOCALE("English_United States.1252");
322#elif LL_DARWIN
323const std::string LLLocale::USER_LOCALE("en_US.iso8859-1");// = LLStringUtil::null;
324const std::string LLLocale::SYSTEM_LOCALE("en_US.iso8859-1");
325#elif LL_SOLARIS
326const std::string LLLocale::USER_LOCALE("en_US.ISO8859-1");
327const std::string LLLocale::SYSTEM_LOCALE("C");
328#else // LL_LINUX likes this
329const std::string LLLocale::USER_LOCALE("en_US.utf8");
330const std::string LLLocale::SYSTEM_LOCALE("C");
331#endif
332
333
334LLLocale::LLLocale(const std::string& locale_string)
335{
336	mPrevLocaleString = setlocale( LC_ALL, NULL );
337	char* new_locale_string = setlocale( LC_ALL, locale_string.c_str());
338	if ( new_locale_string == NULL)
339	{
340		LL_WARNS_ONCE("LLLocale") << "Failed to set locale " << locale_string << LL_ENDL;
341		setlocale(LC_ALL, SYSTEM_LOCALE.c_str());
342	}
343	//else
344	//{
345	//	llinfos << "Set locale to " << new_locale_string << llendl;
346	//}
347}
348
349LLLocale::~LLLocale() 
350{
351	setlocale( LC_ALL, mPrevLocaleString.c_str() );
352}