00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "resmgr.hxx"
00029 #include "xcalc.hxx"
00030 #include "unoglobal.hxx"
00031 #include "tool/global.hxx"
00032 #include "solver.hxx"
00033 #include "scsolver.hrc"
00034
00035 #include "rtl/ustrbuf.hxx"
00036
00037 #include <com/sun/star/beans/PropertyValue.hpp>
00038 #include <com/sun/star/container/XNameAccess.hpp>
00039 #include <com/sun/star/lang/Locale.hpp>
00040 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
00041 #include <com/sun/star/deployment/PackageInformationProvider.hpp>
00042 #include <com/sun/star/deployment/XPackageInformationProvider.hpp>
00043 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
00044 #include <com/sun/star/io/XInputStream.hpp>
00045
00046 #include <vector>
00047 #include <stdio.h>
00048
00049 #define DEBUG_SCSOLVER_RESMGR 0
00050
00051 using namespace ::com::sun::star;
00052 using namespace ::std;
00053
00054 using ::com::sun::star::uno::Any;
00055 using ::com::sun::star::uno::Exception;
00056 using ::com::sun::star::uno::UNO_QUERY;
00057 using ::com::sun::star::uno::UNO_QUERY_THROW;
00058 using ::com::sun::star::uno::Reference;
00059 using ::com::sun::star::uno::Sequence;
00060 using ::com::sun::star::uno::XComponentContext;
00061 using ::com::sun::star::deployment::PackageInformationProvider;
00062 using ::com::sun::star::deployment::XPackageInformationProvider;
00063 using ::com::sun::star::io::XInputStream;
00064 using ::com::sun::star::resource::MissingResourceException;
00065 using ::com::sun::star::ucb::XSimpleFileAccess;
00066
00067 using ::rtl::OUString;
00068 using ::rtl::OUStringBuffer;
00069
00070 namespace scsolver {
00071
00072 StringResMgr::StringResMgr(CalcInterface* pCalc) :
00073 mpCalc(pCalc),
00074 mbStringLoaded(false)
00075 {
00076 }
00077
00078 StringResMgr::~StringResMgr()
00079 {
00080 }
00081
00082 void StringResMgr::loadStrings()
00083 {
00084 init();
00085
00086
00087 vector<PropertiesFile> files;
00088 getPropertiesFiles(files);
00089
00090 vector<PropertiesFile>::const_iterator itr = files.begin(), itrEnd = files.end();
00091 for (; itr != itrEnd; ++itr)
00092 loadStrings(*itr);
00093
00094 #if DEBUG_SCSOLVER_RESMGR
00095 Sequence<OUString> resids = mxStrResMgr->getResourceIDs();
00096 for (sal_Int32 i = 0; i < resids.getLength(); ++i)
00097 {
00098 fprintf(stdout, "StringResMgr::loadStrings: id = '%s'\n",
00099 OUStringToOString(resids[i], RTL_TEXTENCODING_UTF8).getStr());fflush(stdout);
00100 OUString str = mxStrResMgr->resolveString(resids[i]);
00101 fprintf(stdout, "StringResMgr::loadStrings: str = '%s'\n",
00102 OUStringToOString(str, RTL_TEXTENCODING_UTF8).getStr());fflush(stdout);
00103 }
00104 #endif
00105 lang::Locale en_US;
00106 en_US.Language = ascii("en");
00107 en_US.Country = ascii("US");
00108 en_US.Variant = ascii("");
00109 mxStrResMgr->setDefaultLocale(en_US);
00110 mxStrResMgr->setCurrentLocale(getSystemLocale(), true);
00111 }
00112
00113 const OUString StringResMgr::getSystemLocaleString() const
00114 {
00115 Reference<lang::XMultiComponentFactory> xFactory = mpCalc->getServiceManager();
00116
00117 try
00118 {
00119 Reference<lang::XMultiServiceFactory> xConfig(
00120 xFactory->createInstanceWithContext(
00121 ascii("com.sun.star.configuration.ConfigurationProvider"),
00122 mpCalc->getComponentContext() ),
00123 UNO_QUERY_THROW );
00124
00125 beans::PropertyValue prop;
00126 prop.Name = ascii("nodepath");
00127 prop.Value = asciiAny("/org.openoffice.Setup/L10N");
00128 Any any;
00129 any <<= prop;
00130 Sequence<Any> props(1);
00131 props[0] = any;
00132 Reference<container::XNameAccess> xNA(
00133 xConfig->createInstanceWithArguments(
00134 ascii("com.sun.star.configuration.ConfigurationAccess"), props),
00135 UNO_QUERY_THROW );
00136
00137 any = xNA->getByName(ascii("ooLocale"));
00138 OUString localeName;
00139 if (any >>= localeName)
00140
00141 return localeName;
00142 }
00143 catch (const Exception&)
00144 {
00145 Debug("exception caught during locale query.");
00146 }
00147
00148 return OUString();
00149 }
00150
00151 const lang::Locale StringResMgr::getSystemLocale() const
00152 {
00153 lang::Locale locale;
00154
00155 OUString localeStr = getSystemLocaleString();
00156 sal_Int32 n = localeStr.getLength();
00157 const sal_Unicode* chars = localeStr.getStr();
00158 OUStringBuffer buf;
00159 for (sal_Int32 i = 0; i < n; ++i)
00160 {
00161 if (i == 2)
00162
00163 continue;
00164
00165 const sal_Unicode c = chars[i];
00166 buf.append(c);
00167 if (i == 1)
00168 locale.Language = buf.makeStringAndClear();
00169 else if (i == 4)
00170 {
00171 locale.Country = buf.makeStringAndClear();
00172 break;
00173 }
00174 }
00175
00176 #if DEBUG_SCSOLVER_RESMGR || 1
00177 fprintf(stdout, "StringResMgr::getSystemLocale: language = '%s' country = '%s'\n",
00178 OUStringToOString(locale.Language, RTL_TEXTENCODING_UTF8).getStr(),
00179 OUStringToOString(locale.Country, RTL_TEXTENCODING_UTF8).getStr());fflush(stdout);
00180 #endif
00181
00182 return locale;
00183 }
00184
00185 const OUString StringResMgr::getLocaleStr(int resid)
00186 {
00187 return getLocaleStr(getResNameByID(resid));
00188 }
00189
00190 const OUString StringResMgr::getLocaleStr(const OUString& resName)
00191 {
00192 if (!mbStringLoaded)
00193 {
00194 loadStrings();
00195 mbStringLoaded = true;
00196 }
00197
00198 if (!mxStrResMgr.is() || !resName.getLength())
00199 return ascii("(empty)");
00200
00201 try
00202 {
00203 return mxStrResMgr->resolveString(resName);
00204 }
00205 catch (const MissingResourceException&)
00206 {
00207 }
00208
00209 return ascii("(missing)");
00210 }
00211
00212 void StringResMgr::init()
00213 {
00214
00215
00216 Reference<XPackageInformationProvider> xPkgInfo = PackageInformationProvider::get(
00217 mpCalc->getComponentContext() );
00218
00219 OUStringBuffer filePathBuf( xPkgInfo->getPackageLocation(ascii("org.go-oo.CalcSolver")) );
00220 filePathBuf.appendAscii("/translation/");
00221 msBaseTransDirPath = filePathBuf.makeStringAndClear();
00222
00223
00224
00225 Reference<lang::XMultiComponentFactory> xFactory = mpCalc->getServiceManager();
00226
00227 mxStrResMgr.set(
00228 xFactory->createInstanceWithContext(
00229 ascii("com.sun.star.resource.StringResource"),
00230 mpCalc->getComponentContext() ),
00231 UNO_QUERY );
00232
00233 if (!mxStrResMgr.is())
00234 return;
00235 }
00236
00237 OUString StringResMgr::getResNameByID(int resid)
00238 {
00239 static const OUString resNameList[] = {
00240
00241 ascii("SolverDialog.Title"),
00242
00243 ascii("SolverDialog.flModel.Label"),
00244
00245 ascii("SolverDialog.ftTargetCell.Label"),
00246
00247 ascii("SolverDialog.ftObj.Label"),
00248
00249 ascii("SolverDialog.rbMax.Label"),
00250
00251 ascii("SolverDialog.rbMin.Label"),
00252
00253 ascii("SolverDialog.ftDecVars.Label"),
00254
00255 ascii("SolverDialog.flConstraints.Label"),
00256
00257 ascii("ConstEditDialog.Title"),
00258
00259 ascii("ConstEditDialog.ftLeft.Label"),
00260
00261 ascii("ConstEditDialog.ftRight.Label"),
00262
00263 ascii("Common.OK.Label"),
00264
00265 ascii("Common.Cancel.Label"),
00266
00267 ascii("Common.ConstRangeMismatch.Label"),
00268
00269 ascii("SolverDialog.btnConstAdd.Label"),
00270
00271 ascii("SolverDialog.btnConstChange.Label"),
00272
00273 ascii("SolverDialog.btnConstDelete.Label"),
00274
00275 ascii("SolverDialog.btnSolve.Label"),
00276
00277 ascii("SolverDialog.btnReset.Label"),
00278
00279 ascii("SolverDialog.btnOptions.Label"),
00280
00281 ascii("SolverDialog.btnSave.Label"),
00282
00283 ascii("SolverDialog.btnLoad.Label"),
00284
00285 ascii("SolverDialog.btnClose.Label"),
00286
00287 ascii("Common.SolutionNotFound.Label"),
00288
00289 ascii("Common.SolutionFound.Label"),
00290
00291 ascii("Common.CellGeometriesDiffer.Label"),
00292
00293 ascii("Common.MaxIterationReached.Label"),
00294
00295 ascii("Common.StdException.Label"),
00296
00297 ascii("Common.IterationTimedOut.Label"),
00298
00299 ascii("Common.GoalNotSet.Label"),
00300
00301 ascii("OptionDialog.Title"),
00302
00303 ascii("OptionDialog.cbLinear.Label"),
00304
00305 ascii("OptionDialog.cbPositiveValue.Label"),
00306
00307 ascii("OptionDialog.cbIntegerValue.Label"),
00308
00309 ascii("Common.TargetNotSet.Label"),
00310
00311 ascii("Common.DecisionNotSet.Label")
00312 };
00313
00314 if (resid - SCSOLVER_RES_START >= sizeof(resNameList)/sizeof(resNameList[0]))
00315 return ascii("");
00316
00317 return resNameList[resid - SCSOLVER_RES_START];
00318 }
00319
00320 void StringResMgr::loadStrings(const PropertiesFile& propFile)
00321 {
00322 Reference<ucb::XSimpleFileAccess> xFileAccess = getSimpleFileAccess();
00323
00324 if (!xFileAccess.is())
00325 return;
00326
00327 if (!xFileAccess->exists(propFile.FilePath))
00328
00329 return;
00330
00331 Reference<XInputStream> xInStrm = xFileAccess->openFileRead(propFile.FilePath);
00332 if (!xInStrm.is())
00333
00334 return;
00335
00336 sal_Int32 fileSize = xFileAccess->getSize(propFile.FilePath);
00337 Sequence<sal_Int8> bytes;
00338 xInStrm->readBytes(bytes, fileSize);
00339 vector<Entry> entries;
00340 parsePropertiesStream(bytes, entries);
00341 try
00342 {
00343 mxStrResMgr->newLocale(propFile.Locale);
00344 }
00345 catch(const container::ElementExistException&)
00346 {
00347 }
00348 mxStrResMgr->setCurrentLocale(propFile.Locale, false);
00349 vector<Entry>::const_iterator itr = entries.begin(), itrEnd = entries.end();
00350 for (; itr != itrEnd; ++itr)
00351 {
00352 #if DEBUG_SCSOLVER_RESMGR
00353 fprintf(stdout, "StringResMgr::loadStrings: '%s' = '%s'\n",
00354 OUStringToOString(itr->Name, RTL_TEXTENCODING_UTF8).getStr(),
00355 OUStringToOString(itr->Value, RTL_TEXTENCODING_UTF8).getStr());fflush(stdout);
00356 #endif
00357 mxStrResMgr->setString(itr->Name, itr->Value);
00358 }
00359 }
00360
00361 void StringResMgr::getPropertiesFiles(vector<PropertiesFile>& files)
00362 {
00363 Reference<XSimpleFileAccess> xFileAccess = getSimpleFileAccess();
00364 if (!xFileAccess.is())
00365 return;
00366
00367 Sequence<OUString> alldirs = xFileAccess->getFolderContents(msBaseTransDirPath, true);
00368 sal_Int32 dirCount = alldirs.getLength();
00369 if (!dirCount)
00370 return;
00371
00372 const sal_Int32 beginPos = msBaseTransDirPath.getLength();
00373
00374 const sal_Unicode dash = sal_Unicode('-');
00375 const sal_Unicode a = sal_Unicode('a');
00376 const sal_Unicode z = sal_Unicode('z');
00377 const sal_Unicode A = sal_Unicode('A');
00378 const sal_Unicode Z = sal_Unicode('Z');
00379
00380 const OUString ext = ascii(".properties");
00381
00382 files.clear();
00383 for (sal_Int32 i = 0; i < dirCount; ++i)
00384 {
00385 if (!xFileAccess->isFolder(alldirs[i]))
00386 continue;
00387
00388
00389
00390 const sal_Unicode* chars = alldirs[i].getStr();
00391 sal_Int32 strSize = alldirs[i].getLength();
00392 OUStringBuffer buf;
00393 vector<OUString> names;
00394 lang::Locale locale;
00395 bool validName = true;
00396 for (sal_Int32 j = beginPos; j < strSize; ++j)
00397 {
00398 const sal_Unicode c = chars[j];
00399 if (c == dash)
00400 {
00401 if (!buf.getLength())
00402 {
00403 validName = false;
00404 break;
00405 }
00406
00407 if (!locale.Language.getLength())
00408 locale.Language = buf.makeStringAndClear();
00409 else if (!locale.Country.getLength())
00410 locale.Country = buf.makeStringAndClear();
00411 else if (!locale.Variant.getLength())
00412 locale.Variant = buf.makeStringAndClear();
00413 else
00414 {
00415 validName = false;
00416 break;
00417 }
00418 }
00419 else if ( !((a <= c && c <= z) || (A <= c && c <= Z)) )
00420 {
00421
00422 validName = false;
00423 break;
00424 }
00425 else
00426 buf.append(c);
00427 }
00428
00429 if (buf.getLength())
00430 {
00431 if (!locale.Language.getLength())
00432 locale.Language = buf.makeStringAndClear();
00433 else if (!locale.Country.getLength())
00434 locale.Country = buf.makeStringAndClear();
00435 else if (!locale.Variant.getLength())
00436 locale.Variant = buf.makeStringAndClear();
00437 else
00438 validName = false;
00439 }
00440
00441 if (!validName)
00442 continue;
00443
00444 #if DEBUG_SCSOLVER_RESMGR
00445 fprintf(stdout, "StringResMgr::getPropertiesFiles: locale '%s' '%s' '%s'\n",
00446 OUStringToOString(locale.Language, RTL_TEXTENCODING_UTF8).getStr(),
00447 OUStringToOString(locale.Country, RTL_TEXTENCODING_UTF8).getStr(),
00448 OUStringToOString(locale.Variant, RTL_TEXTENCODING_UTF8).getStr());
00449 fflush(stdout);
00450 #endif
00451
00452
00453 Sequence<OUString> allfiles = xFileAccess->getFolderContents(alldirs[i], false);
00454 sal_Int32 fileCount = allfiles.getLength();
00455 for (sal_Int32 j = 0; j < fileCount; ++j)
00456 {
00457 sal_Int32 extPos = allfiles[j].indexOf(ext);
00458 if (extPos < 0 || extPos != allfiles[j].getLength() - ext.getLength())
00459
00460 continue;
00461
00462 PropertiesFile file;
00463 file.FilePath = allfiles[j];
00464 file.Locale = locale;
00465 files.push_back(file);
00466 }
00467 }
00468 }
00469
00470 void StringResMgr::parsePropertiesStream(const Sequence<sal_Int8>& bytes,
00471 vector<Entry>& rEntries)
00472 {
00473 PropStreamParser parser(bytes);
00474 parser.parse();
00475 parser.getEntries(rEntries);
00476
00477 }
00478
00479 Reference<ucb::XSimpleFileAccess> StringResMgr::getSimpleFileAccess()
00480 {
00481 if (!mxFileAccess.is())
00482 {
00483 Reference<lang::XMultiComponentFactory> xFactory = mpCalc->getServiceManager();
00484 mxFileAccess.set(
00485 xFactory->createInstanceWithContext(
00486 ascii("com.sun.star.ucb.SimpleFileAccess"),
00487 mpCalc->getComponentContext() ),
00488 UNO_QUERY );
00489 }
00490
00491 return mxFileAccess;
00492 }
00493
00494
00495
00496 PropStreamParser::PropStreamParser(const Sequence<sal_Int8>& bytes) :
00497 mrBytes(bytes)
00498 {
00499 }
00500
00501 PropStreamParser::~PropStreamParser()
00502 {
00503 }
00504
00505 void PropStreamParser::parse()
00506 {
00507 sal_Int32 size = mrBytes.getLength();
00508 vector<sal_Char> buf;
00509 OUString name, value;
00510 buf.reserve(80);
00511 bool inRHS = false;
00512 bool inNumericID = true;
00513 for (sal_Int32 i = 0; i < size; ++i)
00514 {
00515 switch (mrBytes[i])
00516 {
00517 case '#':
00518 advanceToLinefeed(i);
00519 case 0x0A:
00520 purgeBuffer(value, buf);
00521 pushEntry(name, value);
00522 inRHS = false;
00523 inNumericID = true;
00524 name = OUString();
00525 break;
00526 case '=':
00527 if (inRHS)
00528 buf.push_back(mrBytes[i]);
00529 else
00530 {
00531 inRHS = true;
00532 purgeBuffer(name, buf);
00533 }
00534 break;
00535 case '.':
00536 if (inNumericID)
00537
00538 inNumericID = false;
00539 else
00540 buf.push_back(mrBytes[i]);
00541 break;
00542 case '0':
00543 case '1':
00544 case '2':
00545 case '3':
00546 case '4':
00547 case '5':
00548 case '6':
00549 case '7':
00550 case '8':
00551 case '9':
00552 if (!inNumericID)
00553 buf.push_back(mrBytes[i]);
00554 break;
00555 default:
00556 buf.push_back(mrBytes[i]);
00557 inNumericID = false;
00558 break;
00559 }
00560 }
00561 }
00562
00563 void PropStreamParser::getEntries(vector<StringResMgr::Entry>& rEntries) const
00564 {
00565 vector<StringResMgr::Entry> entries(mEntries.begin(), mEntries.end());
00566 rEntries.swap(entries);
00567 }
00568
00569 void PropStreamParser::advanceToLinefeed(sal_Int32& i) const
00570 {
00571 sal_Int32 size = mrBytes.getLength();
00572 for (; i < size; ++i)
00573 if (mrBytes[i] == 0x0a)
00574 return;
00575 }
00576
00577 void PropStreamParser::purgeBuffer(OUString& rValue, vector<sal_Char>& rBuf) const
00578 {
00579 if (rBuf.empty())
00580 rValue = OUString();
00581 else
00582 {
00583 const sal_Char* p = &rBuf[0];
00584 OUString _value(p, rBuf.size(), RTL_TEXTENCODING_UTF8);
00585 rBuf.clear();
00586 rValue = _value;
00587 }
00588 }
00589
00590 void PropStreamParser::pushEntry(const OUString& name, const OUString& value)
00591 {
00592 if (!name.getLength())
00593 return;
00594
00595 StringResMgr::Entry entry;
00596 entry.Name = name.trim();
00597 entry.Value = value.trim();
00598 mEntries.push_back(entry);
00599 }
00600
00601 }