source/ui/resmgr.cxx

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  The Contents of this file are made available subject to
00004  *  the terms of GNU Lesser General Public License Version 2.1.
00005  *
00006  *
00007  *    GNU Lesser General Public License Version 2.1
00008  *    =============================================
00009  *    Copyright 2005 by Kohei Yoshida.
00010  *    1039 Kingsway Dr., Apex, NC 27502, USA
00011  *
00012  *    This library is free software; you can redistribute it and/or
00013  *    modify it under the terms of the GNU Lesser General Public
00014  *    License version 2.1, as published by the Free Software Foundation.
00015  *
00016  *    This library is distributed in the hope that it will be useful,
00017  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *    Lesser General Public License for more details.
00020  *
00021  *    You should have received a copy of the GNU Lesser General Public
00022  *    License along with this library; if not, write to the Free Software
00023  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00024  *    MA  02111-1307  USA
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     // Get all text files with names formatted this way (/<locale name>/*.properties).
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             // successfully obtained the system locale name!
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             // Ignore the 3rd character ('_').
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     // Get the base directory path where the translation files are stored.
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     // Initialize the UNO string resource manager.
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         // SCSOLVER_STR_MAINDLG_TITLE
00241         ascii("SolverDialog.Title"),
00242         // SCSOLVER_STR_DEFINE_MODEL
00243         ascii("SolverDialog.flModel.Label"),
00244         // SCSOLVER_STR_SET_TARGET_CELL
00245         ascii("SolverDialog.ftTargetCell.Label"),
00246         // SCSOLVER_STR_GOAL
00247         ascii("SolverDialog.ftObj.Label"),
00248         // SCSOLVER_STR_MAXIMIZE
00249         ascii("SolverDialog.rbMax.Label"),
00250         // SCSOLVER_STR_MINIMIZE
00251         ascii("SolverDialog.rbMin.Label"),
00252         // SCSOLVER_STR_DECISIONVAR_CELLS
00253         ascii("SolverDialog.ftDecVars.Label"),
00254         // SCSOLVER_STR_CONSTRAINT_SEP
00255         ascii("SolverDialog.flConstraints.Label"),
00256         // SCSOLVER_STR_CONSTRAINTDLG_TITLE
00257         ascii("ConstEditDialog.Title"),
00258         // SCSOLVER_STR_CELL_REFERENCE
00259         ascii("ConstEditDialog.ftLeft.Label"),
00260         // SCSOLVER_STR_CONSTRAINT
00261         ascii("ConstEditDialog.ftRight.Label"),
00262         // SCSOLVER_STR_BTN_OK
00263         ascii("Common.OK.Label"),
00264         // SCSOLVER_STR_BTN_CANCEL
00265         ascii("Common.Cancel.Label"),
00266         // SCSOLVER_STR_MSG_REF_CON_RANGE_MISMATCH
00267         ascii("Common.ConstRangeMismatch.Label"),
00268         // SCSOLVER_STR_BTN_ADD
00269         ascii("SolverDialog.btnConstAdd.Label"),
00270         // SCSOLVER_STR_BTN_CHANGE
00271         ascii("SolverDialog.btnConstChange.Label"),
00272         // SCSOLVER_STR_BTN_DELETE
00273         ascii("SolverDialog.btnConstDelete.Label"),
00274         // SCSOLVER_STR_BTN_SOLVE
00275         ascii("SolverDialog.btnSolve.Label"),
00276         // SCSOLVER_STR_BTN_RESET
00277         ascii("SolverDialog.btnReset.Label"),
00278         // SCSOLVER_STR_BTN_OPTIONS
00279         ascii("SolverDialog.btnOptions.Label"),
00280         // SCSOLVER_STR_BTN_SAVE_MODEL
00281         ascii("SolverDialog.btnSave.Label"),
00282         // SCSOLVER_STR_BTN_LOAD_MODEL
00283         ascii("SolverDialog.btnLoad.Label"),
00284         // SCSOLVER_STR_BTN_CLOSE
00285         ascii("SolverDialog.btnClose.Label"),
00286         // SCSOLVER_STR_MSG_SOLUTION_NOT_FOUND
00287         ascii("Common.SolutionNotFound.Label"),
00288         // SCSOLVER_STR_MSG_SOLUTION_FOUND
00289         ascii("Common.SolutionFound.Label"),
00290         // SCSOLVER_STR_MSG_CELL_GEOMETRIES_DIFFER
00291         ascii("Common.CellGeometriesDiffer.Label"),
00292         // SCSOLVER_STR_MSG_MAX_ITERATION_REACHED
00293         ascii("Common.MaxIterationReached.Label"),
00294         // SCSOLVER_STR_MSG_STD_EXCEPTION_CAUGHT
00295         ascii("Common.StdException.Label"),
00296         // SCSOLVER_STR_MSG_ITERATION_TIMED_OUT
00297         ascii("Common.IterationTimedOut.Label"),
00298         // SCSOLVER_STR_MSG_GOAL_NOT_SET
00299         ascii("Common.GoalNotSet.Label"),
00300         // SCSOLVER_STR_OPTIONDLG_TITLE
00301         ascii("OptionDialog.Title"),
00302         // SCSOLVER_STR_OPTION_ASSUME_LINEAR
00303         ascii("OptionDialog.cbLinear.Label"),
00304         // SCSOLVER_STR_OPTION_VAR_POSITIVE
00305         ascii("OptionDialog.cbPositiveValue.Label"),
00306         // SCSOLVER_STR_OPTION_VAR_INTEGER
00307         ascii("OptionDialog.cbIntegerValue.Label"),
00308         // SCSOLVER_STR_TARGET_NOT_SET
00309         ascii("Common.TargetNotSet.Label"),
00310         // SCSOLVER_STR_DECISIONVAR_NOT_SET
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         // file does not exist.
00329         return;
00330 
00331     Reference<XInputStream> xInStrm = xFileAccess->openFileRead(propFile.FilePath);
00332     if (!xInStrm.is())
00333         // The input stream is empty.  Bail out.
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         // Parse the directory name to make sure it's a valid locale name.
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                 // only alphabets are allowed.
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         // Pick up all *.properties files.
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                 // the desired extension not found.  skip it.
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: // linefeed
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                     // First dot is encountered.
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 }

Generated on Mon Jul 28 09:13:20 2008 for scsolver by  doxygen 1.5.3