PageRenderTime 13ms CodeModel.GetById 1ms 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
Possible License(s): LGPL-2.1
  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. // NOTE: this is a MINIMAL implementation. The interface will remain, but the implementation will
  27. // (when the time is right) become dynamic and probably use external files.
  28. #include "linden_common.h"
  29. #include "llresmgr.h"
  30. #include "llfontgl.h"
  31. #include "llerror.h"
  32. #include "llstring.h"
  33. LLResMgr::LLResMgr()
  34. {
  35. // Set default
  36. setLocale( LLLOCALE_USA );
  37. }
  38. void LLResMgr::setLocale( LLLOCALE_ID locale_id )
  39. {
  40. mLocale = locale_id;
  41. //RN: for now, use normal 'C' locale for everything but specific UI input/output routines
  42. // switch( locale_id )
  43. // {
  44. // case LLLOCALE_USA:
  45. //#if LL_WINDOWS
  46. // // Windows doesn't use ISO country codes.
  47. // llinfos << "Setting locale to " << setlocale( LC_ALL, "english-usa" ) << llendl;
  48. //#else
  49. // // posix version should work everywhere else.
  50. // llinfos << "Setting locale to " << setlocale( LC_ALL, "en_US" ) << llendl;
  51. //#endif
  52. // break;
  53. // case LLLOCALE_UK:
  54. //#if LL_WINDOWS
  55. // // Windows doesn't use ISO country codes.
  56. // llinfos << "Setting locale to " << setlocale( LC_ALL, "english-uk" ) << llendl;
  57. //#else
  58. // // posix version should work everywhere else.
  59. // llinfos << "Setting locale to " << setlocale( LC_ALL, "en_GB" ) << llendl;
  60. //#endif
  61. // break;
  62. // default:
  63. // llassert(0);
  64. // setLocale(LLLOCALE_USA);
  65. // break;
  66. // }
  67. }
  68. char LLResMgr::getDecimalPoint() const
  69. {
  70. char decimal = localeconv()->decimal_point[0];
  71. #if LL_DARWIN
  72. // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
  73. if(decimal == 0)
  74. {
  75. decimal = '.';
  76. }
  77. #endif
  78. return decimal;
  79. }
  80. char LLResMgr::getThousandsSeparator() const
  81. {
  82. char separator = localeconv()->thousands_sep[0];
  83. #if LL_DARWIN
  84. // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
  85. if(separator == 0)
  86. {
  87. separator = ',';
  88. }
  89. #endif
  90. return separator;
  91. }
  92. char LLResMgr::getMonetaryDecimalPoint() const
  93. {
  94. char decimal = localeconv()->mon_decimal_point[0];
  95. #if LL_DARWIN
  96. // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
  97. if(decimal == 0)
  98. {
  99. decimal = '.';
  100. }
  101. #endif
  102. return decimal;
  103. }
  104. char LLResMgr::getMonetaryThousandsSeparator() const
  105. {
  106. char separator = localeconv()->mon_thousands_sep[0];
  107. #if LL_DARWIN
  108. // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
  109. if(separator == 0)
  110. {
  111. separator = ',';
  112. }
  113. #endif
  114. return separator;
  115. }
  116. // Sets output to a string of integers with monetary separators inserted according to the locale.
  117. std::string LLResMgr::getMonetaryString( S32 input ) const
  118. {
  119. std::string output;
  120. LLLocale locale(LLLocale::USER_LOCALE);
  121. struct lconv *conv = localeconv();
  122. #if LL_DARWIN
  123. // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
  124. // Fake up a conv structure with some reasonable values for the fields this function uses.
  125. struct lconv fakeconv;
  126. char fake_neg[2] = "-";
  127. char fake_mon_group[4] = "\x03\x03\x00"; // commas every 3 digits
  128. if(conv->negative_sign[0] == 0) // Real locales all seem to have something here...
  129. {
  130. fakeconv = *conv; // start with what's there.
  131. switch(mLocale)
  132. {
  133. default: // Unknown -- use the US defaults.
  134. case LLLOCALE_USA:
  135. case LLLOCALE_UK: // UK ends up being the same as US for the items used here.
  136. fakeconv.negative_sign = fake_neg;
  137. fakeconv.mon_grouping = fake_mon_group;
  138. fakeconv.n_sign_posn = 1; // negative sign before the string
  139. break;
  140. }
  141. conv = &fakeconv;
  142. }
  143. #endif
  144. char* negative_sign = conv->negative_sign;
  145. char separator = getMonetaryThousandsSeparator();
  146. char* grouping = conv->mon_grouping;
  147. // Note on mon_grouping:
  148. // Specifies a string that defines the size of each group of digits in formatted monetary quantities.
  149. // The operand for the mon_grouping keyword consists of a sequence of semicolon-separated integers.
  150. // Each integer specifies the number of digits in a group. The initial integer defines the size of
  151. // the group immediately to the left of the decimal delimiter. The following integers define succeeding
  152. // groups to the left of the previous group. If the last integer is not -1, the size of the previous
  153. // group (if any) is repeatedly used for the remainder of the digits. If the last integer is -1, no
  154. // further grouping is performed.
  155. // Note: we assume here that the currency symbol goes on the left. (Hey, it's Lindens! We can just decide.)
  156. BOOL negative = (input < 0 );
  157. BOOL negative_before = negative && (conv->n_sign_posn != 2);
  158. BOOL negative_after = negative && (conv->n_sign_posn == 2);
  159. std::string digits = llformat("%u", abs(input));
  160. if( !grouping || !grouping[0] )
  161. {
  162. if( negative_before )
  163. {
  164. output.append( negative_sign );
  165. }
  166. output.append( digits );
  167. if( negative_after )
  168. {
  169. output.append( negative_sign );
  170. }
  171. return output;
  172. }
  173. S32 groupings[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  174. S32 cur_group;
  175. for( cur_group = 0; grouping[ cur_group ]; cur_group++ )
  176. {
  177. if( grouping[ cur_group ] != ';' )
  178. {
  179. groupings[cur_group] = grouping[ cur_group ];
  180. }
  181. cur_group++;
  182. if( groupings[cur_group] < 0 )
  183. {
  184. break;
  185. }
  186. }
  187. S32 group_count = cur_group;
  188. char reversed_output[20] = ""; /* Flawfinder: ignore */
  189. char forward_output[20] = ""; /* Flawfinder: ignore */
  190. S32 output_pos = 0;
  191. cur_group = 0;
  192. S32 pos = digits.size()-1;
  193. S32 count_within_group = 0;
  194. while( (pos >= 0) && (groupings[cur_group] >= 0) )
  195. {
  196. count_within_group++;
  197. if( count_within_group > groupings[cur_group] )
  198. {
  199. count_within_group = 1;
  200. reversed_output[ output_pos++ ] = separator;
  201. if( (cur_group + 1) >= group_count )
  202. {
  203. break;
  204. }
  205. else
  206. if( groupings[cur_group + 1] > 0 )
  207. {
  208. cur_group++;
  209. }
  210. }
  211. reversed_output[ output_pos++ ] = digits[pos--];
  212. }
  213. while( pos >= 0 )
  214. {
  215. reversed_output[ output_pos++ ] = digits[pos--];
  216. }
  217. reversed_output[ output_pos ] = '\0';
  218. forward_output[ output_pos ] = '\0';
  219. for( S32 i = 0; i < output_pos; i++ )
  220. {
  221. forward_output[ output_pos - 1 - i ] = reversed_output[ i ];
  222. }
  223. if( negative_before )
  224. {
  225. output.append( negative_sign );
  226. }
  227. output.append( forward_output );
  228. if( negative_after )
  229. {
  230. output.append( negative_sign );
  231. }
  232. return output;
  233. }
  234. void LLResMgr::getIntegerString( std::string& output, S32 input ) const
  235. {
  236. // handle special case of input value being zero
  237. if (input == 0)
  238. {
  239. output = "0";
  240. return;
  241. }
  242. // *NOTE: this method does not handle negative input integers correctly
  243. S32 fraction = 0;
  244. std::string fraction_string;
  245. S32 remaining_count = input;
  246. while(remaining_count > 0)
  247. {
  248. fraction = (remaining_count) % 1000;
  249. if (!output.empty())
  250. {
  251. if (fraction == remaining_count)
  252. {
  253. fraction_string = llformat_to_utf8("%d%c", fraction, getThousandsSeparator());
  254. }
  255. else
  256. {
  257. fraction_string = llformat_to_utf8("%3.3d%c", fraction, getThousandsSeparator());
  258. }
  259. output = fraction_string + output;
  260. }
  261. else
  262. {
  263. if (fraction == remaining_count)
  264. {
  265. fraction_string = llformat("%d", fraction);
  266. }
  267. else
  268. {
  269. fraction_string = llformat("%3.3d", fraction);
  270. }
  271. output = fraction_string;
  272. }
  273. remaining_count /= 1000;
  274. }
  275. }
  276. #if LL_WINDOWS
  277. const std::string LLLocale::USER_LOCALE("English_United States.1252");// = LLStringUtil::null;
  278. const std::string LLLocale::SYSTEM_LOCALE("English_United States.1252");
  279. #elif LL_DARWIN
  280. const std::string LLLocale::USER_LOCALE("en_US.iso8859-1");// = LLStringUtil::null;
  281. const std::string LLLocale::SYSTEM_LOCALE("en_US.iso8859-1");
  282. #elif LL_SOLARIS
  283. const std::string LLLocale::USER_LOCALE("en_US.ISO8859-1");
  284. const std::string LLLocale::SYSTEM_LOCALE("C");
  285. #else // LL_LINUX likes this
  286. const std::string LLLocale::USER_LOCALE("en_US.utf8");
  287. const std::string LLLocale::SYSTEM_LOCALE("C");
  288. #endif
  289. LLLocale::LLLocale(const std::string& locale_string)
  290. {
  291. mPrevLocaleString = setlocale( LC_ALL, NULL );
  292. char* new_locale_string = setlocale( LC_ALL, locale_string.c_str());
  293. if ( new_locale_string == NULL)
  294. {
  295. LL_WARNS_ONCE("LLLocale") << "Failed to set locale " << locale_string << LL_ENDL;
  296. setlocale(LC_ALL, SYSTEM_LOCALE.c_str());
  297. }
  298. //else
  299. //{
  300. // llinfos << "Set locale to " << new_locale_string << llendl;
  301. //}
  302. }
  303. LLLocale::~LLLocale()
  304. {
  305. setlocale( LC_ALL, mPrevLocaleString.c_str() );
  306. }