VirtualBox

Changeset 103914 in vbox


Ignore:
Timestamp:
Mar 19, 2024 12:08:58 PM (10 months ago)
Author:
vboxsync
Message:

FE/Qt. bugref:10622. Creating UITranslationEventListener.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
3 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r103795 r103914  
    836836        src/globals/UITextTable.h \
    837837        src/globals/UITranslator.h \
     838        src/globals/UITranslationEventListener.h \
    838839        src/globals/UIVirtualBoxEventHandler.h \
    839840        src/globals/UIVirtualBoxClientEventHandler.h \
     
    14141415        src/globals/UIThreadPool.cpp \
    14151416        src/globals/UITranslator.cpp \
     1417        src/globals/UITranslationEventListener.cpp \
    14161418        src/globals/UIVersion.cpp \
    14171419        src/globals/UIVirtualBoxEventHandler.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp

    r103793 r103914  
    7979#include "UIThreadPool.h"
    8080#include "UITranslator.h"
     81#include "UITranslationEventListener.h"
    8182#include "UIVersion.h"
    8283#include "UIVirtualBoxClientEventHandler.h"
     
    223224    , m_pThreadPoolCloud(0)
    224225    , m_pMediumEnumerator(0)
     226    , m_pTranlationEventListener(0)
    225227{
    226228    /* Assign instance: */
     
    303305
    304306    retranslateUi();
     307
     308    m_pTranlationEventListener = new UITranslationEventListener(this);
    305309
    306310    connect(gEDataManager, &UIExtraDataManager::sigLanguageChange,
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.h

    r103803 r103914  
    6262class UIMediumEnumerator;
    6363class UIThreadPool;
     64class UITranslationEventListener;
    6465
    6566/** QObject subclass containing common GUI functionality. */
     
    680681    /** @} */
    681682
     683    UITranslationEventListener *m_pTranlationEventListener;
    682684    /** Allows for shortcut access. */
    683685    friend UICommon &uiCommon();
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UITranslationEventListener.cpp

    r103906 r103914  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UITranslator class implementation.
     3 * VBox Qt GUI - UITranslationEventListener class implementation.
    44 */
    55
     
    2828/* Qt includes: */
    2929#include <QApplication>
    30 #include <QDir>
    31 #include <QKeySequence>
    32 #include <QRegularExpression>
    33 #ifdef Q_OS_UNIX
    34 # include <QLibraryInfo>
    35 #endif
    3630
    3731/* GUI includes: */
    38 #include "UIConverter.h"
    39 #include "UIMessageCenter.h"
     32#include "UITranslationEventListener.h"
    4033#include "UITranslator.h"
    41 #ifdef VBOX_WS_MAC
    42 # include "VBoxUtils-darwin.h"
    43 #endif
    44 
    45 /* Other VBox includes: */
    46 #include <iprt/assert.h>
    47 #include <iprt/path.h>
    48 #ifdef Q_OS_UNIX
    49 # include <iprt/env.h>
    50 #endif
    51 
    52 /* External includes: */
    53 #include <math.h>
    5434
    5535
    56 /** Port config cache. */
    57 struct PortConfig
     36
     37UITranslationEventListener::UITranslationEventListener(QObject *pParent /* = 0 */)
     38    :QObject(pParent)
    5839{
    59     const char *name;
    60     const ulong IRQ;
    61     const ulong IOBase;
    62 };
    63 
    64 /** Known port config COM ports. */
    65 static const PortConfig kComKnownPorts[] =
    66 {
    67     { "COM1", 4, 0x3F8 },
    68     { "COM2", 3, 0x2F8 },
    69     { "COM3", 4, 0x3E8 },
    70     { "COM4", 3, 0x2E8 },
    71     /* Must not contain an element with IRQ=0 and IOBase=0 used to cause
    72      * toCOMPortName() to return the "User-defined" string for these values. */
    73 };
    74 
    75 
    76 /* static */
    77 UITranslator *UITranslator::s_pTranslator = 0;
    78 bool UITranslator::s_fTranslationInProgress = false;
    79 QString UITranslator::s_strLoadedLanguageId = UITranslator::vboxBuiltInLanguageName();
    80 
    81 /* static */
    82 void UITranslator::loadLanguage(const QString &strLangId /* = QString() */)
    83 {
    84     QString strEffectiveLangId = strLangId.isEmpty()
    85                                ? systemLanguageId()
    86                                : strLangId;
    87     QString strLanguageFileName;
    88     QString strSelectedLangId = vboxBuiltInLanguageName();
    89 
    90     /* If C is selected we change it temporary to en. This makes sure any extra
    91      * "en" translation file will be loaded. This is necessary for loading the
    92      * plural forms of some of our translations. */
    93     bool fResetToC = false;
    94     if (strEffectiveLangId == "C")
    95     {
    96         strEffectiveLangId = "en";
    97         fResetToC = true;
    98     }
    99 
    100     char szNlsPath[RTPATH_MAX];
    101     int rc;
    102 
    103     rc = RTPathAppPrivateNoArch(szNlsPath, sizeof(szNlsPath));
    104     AssertRC(rc);
    105 
    106     QString strNlsPath = QString(szNlsPath) + vboxLanguageSubDirectory();
    107     QDir nlsDir(strNlsPath);
    108 
    109     Assert(!strEffectiveLangId.isEmpty());
    110     if (!strEffectiveLangId.isEmpty() && strEffectiveLangId != vboxBuiltInLanguageName())
    111     {
    112         const QRegularExpression re(vboxLanguageIdRegExp());
    113         const QRegularExpressionMatch mt = re.match(strEffectiveLangId);
    114         /* The language ID should match the regexp completely: */
    115         AssertReturnVoid(mt.capturedStart() == 0);
    116 
    117         QString strStrippedLangId = mt.captured(2);
    118 
    119         if (nlsDir.exists(vboxLanguageFileBase() + strEffectiveLangId + vboxLanguageFileExtension()))
    120         {
    121             strLanguageFileName = nlsDir.absoluteFilePath(vboxLanguageFileBase() +
    122                                                           strEffectiveLangId +
    123                                                           vboxLanguageFileExtension());
    124             strSelectedLangId = strEffectiveLangId;
    125         }
    126         else if (nlsDir.exists(vboxLanguageFileBase() + strStrippedLangId + vboxLanguageFileExtension()))
    127         {
    128             strLanguageFileName = nlsDir.absoluteFilePath(vboxLanguageFileBase() +
    129                                                           strStrippedLangId +
    130                                                           vboxLanguageFileExtension());
    131             strSelectedLangId = strStrippedLangId;
    132         }
    133         else
    134         {
    135             /* Never complain when the default language is requested.  In any
    136              * case, if no explicit language file exists, we will simply
    137              * fall-back to English (built-in). */
    138             if (!strLangId.isNull() && strEffectiveLangId != "en")
    139                 msgCenter().cannotFindLanguage(strEffectiveLangId, strNlsPath);
    140             /* strSelectedLangId remains built-in here: */
    141             AssertReturnVoid(strSelectedLangId == vboxBuiltInLanguageName());
    142         }
    143     }
    144 
    145     /* Lock listener: */
    146     s_fTranslationInProgress = true;
    147     /* A list of translators to install: */
    148     QList<QTranslator*> translators;
    149 
    150     /* Delete the old translator if there is one: */
    151     if (s_pTranslator)
    152     {
    153         /* QTranslator destructor will call qApp->removeTranslator() for
    154          * us. It will also delete all its child translations we attach to it
    155          * below, so we don't have to care about them specially. */
    156         delete s_pTranslator;
    157     }
    158 
    159     /* Load new language files: */
    160     s_pTranslator = new UITranslator(qApp);
    161     Assert(s_pTranslator);
    162     bool fLoadOk = true;
    163     if (s_pTranslator)
    164     {
    165         if (strSelectedLangId != vboxBuiltInLanguageName())
    166         {
    167             Assert(!strLanguageFileName.isNull());
    168             fLoadOk = s_pTranslator->loadFile(strLanguageFileName);
    169         }
    170         /* We install the translator in any case: on failure, this will
    171          * activate an empty translator that will give us English (built-in): */
    172         translators << s_pTranslator;
    173     }
    174     else
    175         fLoadOk = false;
    176 
    177     if (fLoadOk)
    178         s_strLoadedLanguageId = strSelectedLangId;
    179     else
    180     {
    181         msgCenter().cannotLoadLanguage(strLanguageFileName);
    182         s_strLoadedLanguageId = vboxBuiltInLanguageName();
    183     }
    184 
    185     /* Try to load the corresponding Qt translation: */
    186     if (languageId() != vboxBuiltInLanguageName() && languageId() != "en")
    187     {
    188 #ifdef Q_OS_UNIX
    189         // We use system installations of Qt on Linux systems, so first, try
    190         // to load the Qt translation from the system location.
    191         strLanguageFileName = QLibraryInfo::path(QLibraryInfo::TranslationsPath) + "/qt_" +
    192                               languageId() + vboxLanguageFileExtension();
    193         QTranslator *pQtSysTr = new QTranslator(s_pTranslator);
    194         Assert(pQtSysTr);
    195         if (pQtSysTr && pQtSysTr->load(strLanguageFileName))
    196             translators << pQtSysTr;
    197         // Note that the Qt translation supplied by Oracle is always loaded
    198         // afterwards to make sure it will take precedence over the system
    199         // translation (it may contain more decent variants of translation
    200         // that better correspond to VirtualBox UI). We need to load both
    201         // because a newer version of Qt may be installed on the user computer
    202         // and the Oracle version may not fully support it. We don't do it on
    203         // Win32 because we supply a Qt library there and therefore the
    204         // Oracle translation is always the best one. */
    205 #endif
    206         strLanguageFileName = nlsDir.absoluteFilePath(QString("qt_") +
    207                                                       languageId() +
    208                                                       vboxLanguageFileExtension());
    209         QTranslator *pQtTr = new QTranslator(s_pTranslator);
    210         Assert(pQtTr);
    211         if (pQtTr && (fLoadOk = pQtTr->load(strLanguageFileName)))
    212             translators << pQtTr;
    213         /* The below message doesn't fit 100% (because it's an additional
    214          * language and the main one won't be reset to built-in on failure)
    215          * but the load failure is so rare here that it's not worth a separate
    216          * message (but still, having something is better than having none) */
    217         if (!fLoadOk && !strLangId.isNull())
    218             msgCenter().cannotLoadLanguage(strLanguageFileName);
    219     }
    220     if (fResetToC)
    221         s_strLoadedLanguageId = vboxBuiltInLanguageName();
    222 #ifdef VBOX_WS_MAC
    223     // Qt doesn't translate the items in the Application menu initially.
    224     // Manually trigger an update.
    225     ::darwinRetranslateAppMenu();
    226 #endif
    227 
    228     /* Iterate through all the translators: */
    229     for (int i = 0; i < translators.size(); ++i)
    230     {
    231         /* Unlock listener before the last one translator: */
    232         if (i == translators.size() - 1)
    233         {
    234             QCoreApplication::sendPostedEvents(0, QEvent::LanguageChange);
    235             s_fTranslationInProgress = false;
    236         }
    237 
    238         /* Install current one: */
    239         qApp->installTranslator(translators.at(i));
    240     }
    241 
    242     /* Unlock listener in case if it's still locked: */
    243     s_fTranslationInProgress = false;
     40    qApp->installEventFilter(this);
    24441}
    24542
    246 /* static */
    247 QString UITranslator::vboxLanguageSubDirectory()
     43bool UITranslationEventListener::eventFilter(QObject *pObject, QEvent *pEvent)
    24844{
    249     return "/nls";
     45    if (   !UITranslator::isTranslationInProgress()
     46           && pEvent->type() == QEvent::LanguageChange)
     47    {
     48        //&& (pObject == qApp || pObject == this))
     49        emit sigRetranslate();
     50    }
     51    /* Call to base-class: */
     52    return QObject::eventFilter(pObject, pEvent);
    25053}
    251 
    252 /* static */
    253 QString UITranslator::vboxLanguageFileBase()
    254 {
    255     return "VirtualBox_";
    256 }
    257 
    258 /* static */
    259 QString UITranslator::vboxLanguageFileExtension()
    260 {
    261     return ".qm";
    262 }
    263 
    264 /* static */
    265 QString UITranslator::vboxLanguageIdRegExp()
    266 {
    267     return "(([a-z]{2})(?:_([A-Z]{2}))?)|(C)";
    268 }
    269 
    270 /* static */
    271 QString UITranslator::vboxBuiltInLanguageName()
    272 {
    273     return "C";
    274 }
    275 
    276 /* static */
    277 QString UITranslator::languageId()
    278 {
    279     /* Note that it may not match with UIExtraDataManager::languageId() if the specified language cannot be loaded.
    280      *
    281      * If the built-in language is active, this method returns "C". "C" is treated as the built-in language for
    282      * simplicity -- the C locale is used in unix environments as a fallback when the requested locale is invalid.
    283      * This way we don't need to process both the "built_in" language and the "C" language (which is a valid
    284      * environment setting) separately. */
    285 
    286     return s_strLoadedLanguageId;
    287 }
    288 
    289 /* static */
    290 QString UITranslator::yearsToString(uint32_t cVal)
    291 {
    292     return QApplication::translate("UITranslator", "%n year(s)", "", cVal);
    293 }
    294 
    295 /* static */
    296 QString UITranslator::monthsToString(uint32_t cVal)
    297 {
    298     return QApplication::translate("UITranslator", "%n month(s)", "", cVal);
    299 }
    300 
    301 /* static */
    302 QString UITranslator::daysToString(uint32_t cVal)
    303 {
    304     return QApplication::translate("UITranslator", "%n day(s)", "", cVal);
    305 }
    306 
    307 /* static */
    308 QString UITranslator::hoursToString(uint32_t cVal)
    309 {
    310     return QApplication::translate("UITranslator", "%n hour(s)", "", cVal);
    311 }
    312 
    313 /* static */
    314 QString UITranslator::minutesToString(uint32_t cVal)
    315 {
    316     return QApplication::translate("UITranslator", "%n minute(s)", "", cVal);
    317 }
    318 
    319 /* static */
    320 QString UITranslator::secondsToString(uint32_t cVal)
    321 {
    322     return QApplication::translate("UITranslator", "%n second(s)", "", cVal);
    323 }
    324 
    325 /* static */
    326 QString UITranslator::yearsToStringAgo(uint32_t cVal)
    327 {
    328     return QApplication::translate("UITranslator", "%n year(s) ago", "", cVal);
    329 }
    330 
    331 /* static */
    332 QString UITranslator::monthsToStringAgo(uint32_t cVal)
    333 {
    334     return QApplication::translate("UITranslator", "%n month(s) ago", "", cVal);
    335 }
    336 
    337 /* static */
    338 QString UITranslator::daysToStringAgo(uint32_t cVal)
    339 {
    340     return QApplication::translate("UITranslator", "%n day(s) ago", "", cVal);
    341 }
    342 
    343 /* static */
    344 QString UITranslator::hoursToStringAgo(uint32_t cVal)
    345 {
    346     return QApplication::translate("UITranslator", "%n hour(s) ago", "", cVal);
    347 }
    348 
    349 /* static */
    350 QString UITranslator::minutesToStringAgo(uint32_t cVal)
    351 {
    352     return QApplication::translate("UITranslator", "%n minute(s) ago", "", cVal);
    353 }
    354 
    355 /* static */
    356 QString UITranslator::secondsToStringAgo(uint32_t cVal)
    357 {
    358     return QApplication::translate("UITranslator", "%n second(s) ago", "", cVal);
    359 }
    360 
    361 /* static */
    362 QString UITranslator::decimalSep()
    363 {
    364     return QString(QLocale::system().decimalPoint());
    365 }
    366 
    367 /* static */
    368 QString UITranslator::sizeRegexp()
    369 {
    370     /* This regexp will capture 5 groups of text:
    371      * - cap(1): integer number in case when no decimal point is present
    372      *           (if empty, it means that decimal point is present)
    373      * - cap(2): size suffix in case when no decimal point is present (may be empty)
    374      * - cap(3): integer number in case when decimal point is present (may be empty)
    375      * - cap(4): fraction number (hundredth) in case when decimal point is present
    376      * - cap(5): size suffix in case when decimal point is present (note that
    377      *           B cannot appear there). */
    378 
    379     const QString strRegexp =
    380         QString("^(?:(?:(\\d+)(?:\\s?(%2|%3|%4|%5|%6|%7))?)|(?:(\\d*)%1(\\d{1,2})(?:\\s?(%3|%4|%5|%6|%7))))$")
    381             .arg(decimalSep())
    382             .arg(tr("B", "size suffix Bytes"))
    383             .arg(tr("KB", "size suffix KBytes=1024 Bytes"))
    384             .arg(tr("MB", "size suffix MBytes=1024 KBytes"))
    385             .arg(tr("GB", "size suffix GBytes=1024 MBytes"))
    386             .arg(tr("TB", "size suffix TBytes=1024 GBytes"))
    387             .arg(tr("PB", "size suffix PBytes=1024 TBytes"));
    388     return strRegexp;
    389 }
    390 
    391 /* static */
    392 quint64 UITranslator::parseSize(const QString &strText)
    393 {
    394     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    395     const QRegularExpression re(sizeRegexp());
    396     const QRegularExpressionMatch mt = re.match(strText);
    397     if (mt.hasMatch())
    398     {
    399         QString strInteger = mt.captured(1);
    400         QString strHundred;
    401         QString strSuff = mt.captured(2);
    402         if (strInteger.isEmpty())
    403         {
    404             strInteger = mt.captured(3);
    405             strHundred = mt.captured(4);
    406             strSuff = mt.captured(5);
    407         }
    408 
    409         quint64 uDenominator = 0;
    410         if (strSuff.isEmpty() || strSuff == tr("B", "size suffix Bytes"))
    411             uDenominator = 1;
    412         else if (strSuff == tr("KB", "size suffix KBytes=1024 Bytes"))
    413             uDenominator = _1K;
    414         else if (strSuff == tr("MB", "size suffix MBytes=1024 KBytes"))
    415             uDenominator = _1M;
    416         else if (strSuff == tr("GB", "size suffix GBytes=1024 MBytes"))
    417             uDenominator = _1G;
    418         else if (strSuff == tr("TB", "size suffix TBytes=1024 GBytes"))
    419             uDenominator = _1T;
    420         else if (strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    421             uDenominator = _1P;
    422 
    423         quint64 iInteger = strInteger.toULongLong();
    424         if (uDenominator == 1)
    425             return iInteger;
    426 
    427         quint64 iHundred = strHundred.leftJustified(2, '0').toULongLong();
    428         iHundred = iHundred * uDenominator / 100;
    429         iInteger = iInteger * uDenominator + iHundred;
    430         return iInteger;
    431     }
    432     else
    433         return 0;
    434 }
    435 
    436 /* static */
    437 SizeSuffix UITranslator::parseSizeSuffix(const QString &strText)
    438 {
    439     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    440     const QRegularExpression re(sizeRegexp());
    441     const QRegularExpressionMatch mt = re.match(strText);
    442     if (mt.hasMatch())
    443     {
    444         QString strInteger = mt.captured(1);
    445         QString strSuff = mt.captured(2);
    446         if (strInteger.isEmpty())
    447         {
    448             strInteger = mt.captured(3);
    449             strSuff = mt.captured(5);
    450         }
    451 
    452         SizeSuffix enmSizeSuffix = SizeSuffix_Byte;
    453 
    454         if (strSuff.isEmpty() || strSuff == tr("B", "size suffix Bytes"))
    455             enmSizeSuffix = SizeSuffix_Byte;
    456         else if (strSuff == tr("KB", "size suffix KBytes=1024 Bytes"))
    457             enmSizeSuffix = SizeSuffix_KiloByte;
    458         else if (strSuff == tr("MB", "size suffix MBytes=1024 KBytes"))
    459             enmSizeSuffix = SizeSuffix_MegaByte;
    460         else if (strSuff == tr("GB", "size suffix GBytes=1024 MBytes"))
    461             enmSizeSuffix = SizeSuffix_GigaByte;
    462         else if (strSuff == tr("TB", "size suffix TBytes=1024 GBytes"))
    463             enmSizeSuffix = SizeSuffix_TeraByte;
    464         else if (strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    465             enmSizeSuffix = SizeSuffix_PetaByte;
    466         return enmSizeSuffix;
    467     }
    468     else
    469         return SizeSuffix_Byte;
    470 }
    471 
    472 /* static */
    473 bool UITranslator::hasSizeSuffix(const QString &strText)
    474 {
    475     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    476     const QRegularExpression re(sizeRegexp());
    477     const QRegularExpressionMatch mt = re.match(strText);
    478     if (mt.hasMatch())
    479     {
    480         QString strInteger = mt.captured(1);
    481         QString strSuff = mt.captured(2);
    482         if (strInteger.isEmpty())
    483         {
    484             strInteger = mt.captured(3);
    485             strSuff = mt.captured(5);
    486         }
    487 
    488         if (strSuff.isEmpty())
    489             return false;
    490         if (strSuff == tr("B", "size suffix Bytes") ||
    491             strSuff == tr("KB", "size suffix KBytes=1024 Bytes") ||
    492             strSuff == tr("MB", "size suffix MBytes=1024 KBytes") ||
    493             strSuff == tr("GB", "size suffix GBytes=1024 MBytes") ||
    494             strSuff == tr("TB", "size suffix TBytes=1024 GBytes") ||
    495             strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    496             return true;
    497         return false;
    498     }
    499     else
    500         return false;
    501 }
    502 
    503 /* static */
    504 QString UITranslator::formatSize(quint64 uSize, uint cDecimal /* = 2 */,
    505                                  FormatSize enmMode /* = FormatSize_Round */)
    506 {
    507     /* Text will be in form of B|KB|MB|GB|TB|PB.
    508      *
    509      * When enmMode is FormatSize_Round, the result is rounded to the
    510      *              closest number containing @a aDecimal decimal digits.
    511      * When enmMode is FormatSize_RoundDown, the result is rounded to the
    512      *              largest number with @a aDecimal decimal digits that is not greater than
    513      *              the result. This guarantees that converting the resulting string back to
    514      *              the integer value in bytes will not produce a value greater that the
    515      *              initial size parameter.
    516      * When enmMode is FormatSize_RoundUp, the result is rounded to the
    517      *              smallest number with @a aDecimal decimal digits that is not less than the
    518      *              result. This guarantees that converting the resulting string back to the
    519      *              integer value in bytes will not produce a value less that the initial
    520      *              size parameter. */
    521 
    522     quint64 uDenominator = 0;
    523     int iSuffix = 0;
    524 
    525     if (uSize < _1K)
    526     {
    527         uDenominator = 1;
    528         iSuffix = 0;
    529     }
    530     else if (uSize < _1M)
    531     {
    532         uDenominator = _1K;
    533         iSuffix = 1;
    534     }
    535     else if (uSize < _1G)
    536     {
    537         uDenominator = _1M;
    538         iSuffix = 2;
    539     }
    540     else if (uSize < _1T)
    541     {
    542         uDenominator = _1G;
    543         iSuffix = 3;
    544     }
    545     else if (uSize < _1P)
    546     {
    547         uDenominator = _1T;
    548         iSuffix = 4;
    549     }
    550     else
    551     {
    552         uDenominator = _1P;
    553         iSuffix = 5;
    554     }
    555 
    556     quint64 uInteger = uSize / uDenominator;
    557     quint64 uDecimal = uSize % uDenominator;
    558     quint64 uMult = 1;
    559     for (uint i = 0; i < cDecimal; ++i)
    560         uMult *= 10;
    561 
    562     QString strNumber;
    563     if (uDenominator > 1)
    564     {
    565         if (uDecimal)
    566         {
    567             uDecimal *= uMult;
    568             /* Not greater: */
    569             if (enmMode == FormatSize_RoundDown)
    570                 uDecimal = uDecimal / uDenominator;
    571             /* Not less: */
    572             else if (enmMode == FormatSize_RoundUp)
    573                 uDecimal = (uDecimal + uDenominator - 1) / uDenominator;
    574             /* Nearest: */
    575             else
    576                 uDecimal = (uDecimal + uDenominator / 2) / uDenominator;
    577         }
    578         /* Check for the fractional part overflow due to rounding: */
    579         if (uDecimal == uMult)
    580         {
    581             uDecimal = 0;
    582             ++uInteger;
    583             /* Check if we've got 1024 XB after rounding and scale down if so: */
    584             if (uInteger == 1024 && iSuffix + 1 < (int)SizeSuffix_Max)
    585             {
    586                 uInteger /= 1024;
    587                 ++iSuffix;
    588             }
    589         }
    590         strNumber = QString::number(uInteger);
    591         if (cDecimal)
    592             strNumber += QString("%1%2").arg(decimalSep())
    593                                         .arg(QString::number(uDecimal).rightJustified(cDecimal, '0'));
    594     }
    595     else
    596     {
    597         strNumber = QString::number(uInteger);
    598     }
    599 
    600     return QString("%1 %2").arg(strNumber).arg(gpConverter->toString(static_cast<SizeSuffix>(iSuffix)));
    601 }
    602 
    603 /* static */
    604 QString UITranslator::addMetricSuffixToNumber(quint64 uNumber)
    605 {
    606     if (uNumber <= 0)
    607         return QString();
    608     /* See https://en.wikipedia.org/wiki/Metric_prefix for metric suffixes:*/
    609     char suffixes[] = {'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'};
    610     int zeroCount = (int)log10((long double)uNumber);
    611     if (zeroCount < 3)
    612         return QString::number(uNumber);
    613     int h = 3 * (zeroCount / 3);
    614     char result[128];
    615     sprintf(result, "%.2f", uNumber / (float)pow((double)10, h));
    616     return QString("%1%2").arg(result).arg(suffixes[h / 3 - 1]);
    617 }
    618 
    619 /* static */
    620 QStringList UITranslator::COMPortNames()
    621 {
    622     QStringList list;
    623     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    624         list << kComKnownPorts[i].name;
    625 
    626     return list;
    627 }
    628 
    629 /* static */
    630 QString UITranslator::toCOMPortName(ulong uIRQ, ulong uIOBase)
    631 {
    632     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    633         if (kComKnownPorts[i].IRQ == uIRQ &&
    634             kComKnownPorts[i].IOBase == uIOBase)
    635             return kComKnownPorts[i].name;
    636 
    637     return tr("User-defined", "serial port");;
    638 }
    639 
    640 /* static */
    641 bool UITranslator::toCOMPortNumbers(const QString &strName, ulong &uIRQ, ulong &uIOBase)
    642 {
    643     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    644         if (strcmp(kComKnownPorts[i].name, strName.toUtf8().data()) == 0)
    645         {
    646             uIRQ = kComKnownPorts[i].IRQ;
    647             uIOBase = kComKnownPorts[i].IOBase;
    648             return true;
    649         }
    650 
    651     return false;
    652 }
    653 
    654 /* Regular expressions used by both highlight and emphasize.  They use the
    655    same prefix and suffix expression.  Unfortunately, QRegularExpression isn't
    656    thread safe, so we only store the string contstants here. */
    657 /** @todo qt6: Both these had bogus suffix sets '[:.-!);]', I've changed them to '[-:.!);]', hope that's correct. */
    658 static char const g_szRxSingleQuotes[] = "((?:^|\\s)[(]?)"
    659                                          "'([^']*)'"
    660                                          "(?=[-:.!);]?(?:\\s|$))";
    661 static const char g_szRxUuid[]         = "((?:^|\\s)[(]?)"
    662                                          "(\\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\})"
    663                                          "(?=[-:.!);]?(?:\\s|$))";
    664 
    665 /* static */
    666 QString UITranslator::highlight(QString strText, bool fToolTip /* = false */)
    667 {
    668     /* We should reformat the input strText so that:
    669      * - strings in single quotes will be put inside <nobr> and marked
    670      *   with blue color;
    671      * - UUIDs be put inside <nobr> and marked
    672      *   with green color;
    673      * - replaces new line chars with </p><p> constructs to form paragraphs
    674      *   (note that <p\> and </p> are not appended to the beginning and to the
    675      *    end of the string respectively, to allow the result be appended
    676      *    or prepended to the existing paragraph).
    677      *
    678      *  If @a fToolTip is true, colouring is not applied, only the <nobr> tag
    679      *  is added. Also, new line chars are replaced with <br> instead of <p>. */
    680 
    681     QString strFont;
    682     QString uuidFont;
    683     QString endFont;
    684     if (!fToolTip)
    685     {
    686         strFont = "<font color=#0000CC>";
    687         uuidFont = "<font color=#008000>";
    688         endFont = "</font>";
    689     }
    690 
    691     /* Replace special entities, '&' -- first! */
    692     strText.replace('&', "&amp;");
    693     strText.replace('<', "&lt;");
    694     strText.replace('>', "&gt;");
    695     strText.replace('\"', "&quot;");
    696 
    697     /* Mark strings in single quotes with color: */
    698     strText.replace(QRegularExpression(g_szRxSingleQuotes), QString("\\1%1<nobr>'\\2'</nobr>%2").arg(strFont).arg(endFont));
    699 
    700     /* Mark UUIDs with color: */
    701     strText.replace(QRegularExpression(g_szRxUuid), QString("\\1%1<nobr>\\2</nobr>%2").arg(uuidFont).arg(endFont));
    702 
    703     /* Split to paragraphs at \n chars: */
    704     if (!fToolTip)
    705         strText.replace('\n', "</p><p>");
    706     else
    707         strText.replace('\n', "<br>");
    708 
    709     return strText;
    710 }
    711 
    712 /* static */
    713 QString UITranslator::emphasize(QString strText)
    714 {
    715     /* We should reformat the input string @a strText so that:
    716      * - strings in single quotes will be put inside \<nobr\> and marked
    717      *   with bold style;
    718      * - UUIDs be put inside \<nobr\> and marked
    719      *   with italic style;
    720      * - replaces new line chars with \</p\>\<p\> constructs to form paragraphs
    721      *   (note that \<p\> and \</p\> are not appended to the beginning and to the
    722      *    end of the string respectively, to allow the result be appended
    723      *    or prepended to the existing paragraph). */
    724 
    725     QString strEmphStart("<b>");
    726     QString strEmphEnd("</b>");
    727     QString uuidEmphStart("<i>");
    728     QString uuidEmphEnd("</i>");
    729 
    730     /* Replace special entities, '&' -- first! */
    731     strText.replace('&', "&amp;");
    732     strText.replace('<', "&lt;");
    733     strText.replace('>', "&gt;");
    734     strText.replace('\"', "&quot;");
    735 
    736     /* Mark strings in single quotes with bold style: */
    737     strText.replace(QRegularExpression(g_szRxSingleQuotes), QString("\\1%1<nobr>'\\2'</nobr>%2").arg(strEmphStart).arg(strEmphEnd));
    738 
    739     /* Mark UUIDs with italic style: */
    740     strText.replace(QRegularExpression(g_szRxUuid), QString("\\1%1<nobr>\\2</nobr>%2").arg(uuidEmphStart).arg(uuidEmphEnd));
    741 
    742     /* Split to paragraphs at \n chars: */
    743     strText.replace('\n', "</p><p>");
    744 
    745     return strText;
    746 }
    747 
    748 /* static */
    749 QString UITranslator::removeAccelMark(QString strText)
    750 {
    751     /* In order to support accelerators used in non-alphabet languages
    752      * (e.g. Japanese) that has a form of "(&<L>)" (where <L> is a latin letter),
    753      * this method first searches for this pattern and, if found, removes it as a
    754      * whole. If such a pattern is not found, then the '&' character is simply
    755      * removed from the string. */
    756 
    757     const QRegularExpression re("\\(&[a-zA-Z]\\)");
    758     const QRegularExpressionMatch mt = re.match(strText);
    759     int iPos = mt.capturedStart();
    760     if (iPos >= 0)
    761         strText.remove(iPos, mt.capturedLength());
    762     else
    763     {
    764         iPos = strText.indexOf('&');
    765         if (iPos >= 0)
    766             strText.remove(iPos, 1);
    767     }
    768 
    769     return strText;
    770 }
    771 
    772 /* static */
    773 QString UITranslator::insertKeyToActionText(const QString &strText, const QString &strKey)
    774 {
    775 #ifdef VBOX_WS_MAC
    776     QString strPattern("%1 (Host+%2)");
    777 #else
    778     QString strPattern("%1 \tHost+%2");
    779 #endif
    780     if (   strKey.isEmpty()
    781         || strKey.compare("None", Qt::CaseInsensitive) == 0)
    782         return strText;
    783     else
    784         return strPattern.arg(strText).arg(QKeySequence(strKey).toString(QKeySequence::NativeText));
    785 }
    786 
    787 /* static */
    788 bool UITranslator::isTranslationInProgress()
    789 {
    790     return s_fTranslationInProgress;
    791 }
    792 
    793 /* static */
    794 QString UITranslator::byteStringToMegaByteString(const QString &strByteString)
    795 {
    796     if (strByteString.isEmpty())
    797         return QString();
    798     bool fConversionSuccess = false;
    799     qulonglong uByte = strByteString.toULongLong(&fConversionSuccess);
    800     AssertReturn(fConversionSuccess, QString());
    801     return QString::number(uByte / _1M);
    802 }
    803 
    804 /* static */
    805 QString UITranslator::megabyteStringToByteString(const QString &strMegaByteString)
    806 {
    807     if (strMegaByteString.isEmpty())
    808         return QString();
    809     bool fConversionSuccess = false;
    810     qulonglong uMegaByte = strMegaByteString.toULongLong(&fConversionSuccess);
    811     AssertReturn(fConversionSuccess, QString());
    812     return QString::number(uMegaByte * _1M);
    813 }
    814 
    815 UITranslator::UITranslator(QObject *pParent /* = 0 */)
    816     : QTranslator(pParent)
    817 {
    818 }
    819 
    820 bool UITranslator::loadFile(const QString &strFileName)
    821 {
    822     QFile file(strFileName);
    823     if (!file.open(QIODevice::ReadOnly))
    824         return false;
    825     m_data = file.readAll();
    826     return load((uchar*)m_data.data(), m_data.size());
    827 }
    828 
    829 /* static */
    830 QString UITranslator::languageName()
    831 {
    832     /* Returns "English" if no translation is installed
    833      * or if the translation file is invalid. */
    834     return QApplication::translate("@@@", "English",
    835                                    "Native language name");
    836 }
    837 
    838 /* static */
    839 QString UITranslator::languageCountry()
    840 {
    841     /* Returns "--" if no translation is installed or if the translation file
    842      * is invalid, or if the language is independent on the country. */
    843     return QApplication::translate("@@@", "--",
    844                                    "Native language country name "
    845                                    "(empty if this language is for all countries)");
    846 }
    847 
    848 /* static */
    849 QString UITranslator::languageNameEnglish()
    850 {
    851     /* Returns "English" if no translation is installed
    852      * or if the translation file is invalid. */
    853     return QApplication::translate("@@@", "English",
    854                                    "Language name, in English");
    855 }
    856 
    857 /* static */
    858 QString UITranslator::languageCountryEnglish()
    859 {
    860     /* Returns "--" if no translation is installed or if the translation file
    861      * is invalid, or if the language is independent on the country. */
    862     return QApplication::translate("@@@", "--",
    863                                    "Language country name, in English "
    864                                    "(empty if native country name is empty)");
    865 }
    866 
    867 /* static */
    868 QString UITranslator::languageTranslators()
    869 {
    870     /* Returns "Oracle Corporation" if no translation is installed or if the translation file
    871      * is invalid, or if the translation is supplied by Oracle Corporation. */
    872     return QApplication::translate("@@@", "Oracle Corporation",
    873                                    "Comma-separated list of translators");
    874 }
    875 
    876 /* static */
    877 QString UITranslator::systemLanguageId()
    878 {
    879     /* This does exactly the same as QLocale::system().name() but corrects its wrong behavior on Linux systems
    880      * (LC_NUMERIC for some strange reason takes precedence over any other locale setting in the QLocale::system()
    881      * implementation). This implementation first looks at LC_ALL (as defined by SUS), then looks at LC_MESSAGES
    882      * which is designed to define a language for program messages in case if it differs from the language for
    883      * other locale categories. Then it looks for LANG and finally falls back to QLocale::system().name().
    884      *
    885      * The order of precedence is well defined here:
    886      * http://opengroup.org/onlinepubs/007908799/xbd/envvar.html
    887      *
    888      * This method will return "C" when the requested locale is invalid or when the "C" locale is set explicitly. */
    889 
    890 #if defined(VBOX_WS_MAC)
    891     // QLocale return the right id only if the user select the format
    892     // of the language also. So we use our own implementation */
    893     return ::darwinSystemLanguage();
    894 #elif defined(Q_OS_UNIX)
    895     const char *pszValue = RTEnvGet("LC_ALL");
    896     if (pszValue == 0)
    897         pszValue = RTEnvGet("LC_MESSAGES");
    898     if (pszValue == 0)
    899         pszValue = RTEnvGet("LANG");
    900     if (pszValue != 0)
    901         return QLocale(pszValue).name();
    902 #endif
    903     return QLocale::system().name();
    904 }
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UITranslationEventListener.h

    r103906 r103914  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UITranslator class declaration.
     3 * VBox Qt GUI - UITranslationEventListener class declaration.
    44 */
    55
     
    2626 */
    2727
    28 #ifndef FEQT_INCLUDED_SRC_globals_UITranslator_h
    29 #define FEQT_INCLUDED_SRC_globals_UITranslator_h
     28#ifndef FEQT_INCLUDED_SRC_globals_UITranslationEventListener_h
     29#define FEQT_INCLUDED_SRC_globals_UITranslationEventListener_h
    3030#ifndef RT_WITHOUT_PRAGMA_ONCE
    3131# pragma once
     
    3333
    3434/* Qt includes: */
    35 #include <QTranslator>
     35#include <QObject>
    3636
    37 /* GUI includes: */
    3837#include "UILibraryDefs.h"
    3938
    40 /** Size suffixes. */
    41 enum SizeSuffix
    42 {
    43     SizeSuffix_Byte = 0,
    44     SizeSuffix_KiloByte,
    45     SizeSuffix_MegaByte,
    46     SizeSuffix_GigaByte,
    47     SizeSuffix_TeraByte,
    48     SizeSuffix_PetaByte,
    49     SizeSuffix_Max
    50 };
    51 
    52 /** QTranslator subclass for VBox needs. */
    53 class SHARED_LIBRARY_STUFF UITranslator : public QTranslator
     39class SHARED_LIBRARY_STUFF UITranslationEventListener : public QObject
    5440{
    5541    Q_OBJECT;
    5642
     43signals:
     44
     45    void sigRetranslate();
     46
    5747public:
    5848
    59     /** Size formatting types. */
    60     enum FormatSize
    61     {
    62         FormatSize_Round,
    63         FormatSize_RoundDown,
    64         FormatSize_RoundUp
    65     };
     49    UITranslationEventListener(QObject *pParent = 0);
    6650
    67     /** Loads the language by language ID.
    68       * @param  strLangId  Brings the language ID in in form of xx_YY.
    69       *                    QString() means the system default language. */
    70     static void loadLanguage(const QString &strLangId = QString());
     51protected:
    7152
    72     /** Returns VBox language sub-directory. */
    73     static QString vboxLanguageSubDirectory();
    74     /** Returns VBox language file-base. */
    75     static QString vboxLanguageFileBase();
    76     /** Returns VBox language file-extension. */
    77     static QString vboxLanguageFileExtension();
    78     /** Returns VBox language ID reg-exp. */
    79     static QString vboxLanguageIdRegExp();
    80     /** Returns built in language name. */
    81     static QString vboxBuiltInLanguageName();
    82 
    83     /** Returns the loaded (active) language ID. */
    84     static QString languageId();
    85 
    86     /** Returns tr("%n year(s)"). */
    87     static QString yearsToString(uint32_t cVal);
    88     /** Returns tr("%n month(s)"). */
    89     static QString monthsToString(uint32_t cVal);
    90     /** Returns tr("%n day(s)"). */
    91     static QString daysToString(uint32_t cVal);
    92     /** Returns tr("%n hour(s)"). */
    93     static QString hoursToString(uint32_t cVal);
    94     /** Returns tr("%n minute(s)"). */
    95     static QString minutesToString(uint32_t cVal);
    96     /** Returns tr("%n second(s)"). */
    97     static QString secondsToString(uint32_t cVal);
    98 
    99     /** Returns tr("%n year(s) ago"). */
    100     static QString yearsToStringAgo(uint32_t cVal);
    101     /** Returns tr("%n month(s) ago"). */
    102     static QString monthsToStringAgo(uint32_t cVal);
    103     /** Returns tr("%n day(s) ago"). */
    104     static QString daysToStringAgo(uint32_t cVal);
    105     /** Returns tr("%n hour(s) ago"). */
    106     static QString hoursToStringAgo(uint32_t cVal);
    107     /** Returns tr("%n minute(s) ago"). */
    108     static QString minutesToStringAgo(uint32_t cVal);
    109     /** Returns tr("%n second(s) ago"). */
    110     static QString secondsToStringAgo(uint32_t cVal);
    111 
    112     /** Returns the decimal separator for the current locale. */
    113     static QString decimalSep();
    114     /** Returns the regexp string that defines the format of the human-readable size representation. */
    115     static QString sizeRegexp();
    116     /** Parses the given size strText and returns the size value in bytes. */
    117     static quint64 parseSize(const QString &strText);
    118     /** Parses the given size strText and returns the size suffix. */
    119     static SizeSuffix parseSizeSuffix(const QString &strText);
    120     /** Parses the given string @a strText and returns true if it includes a size suffix. */
    121     static bool hasSizeSuffix(const QString &strText);
    122     /** Formats the given @a uSize value in bytes to a human readable string.
    123       * @param  uSize     Brings the size value in bytes.
    124       * @param  enmMode   Brings the conversion mode.
    125       * @param  cDecimal  Brings the number of decimal digits in result. */
    126     static QString formatSize(quint64 uSize, uint cDecimal = 2, FormatSize enmMode = FormatSize_Round);
    127     /** Formats the given @a uNumber to that 'k' is added for thousand, 'M' for million and so on. */
    128     static QString addMetricSuffixToNumber(quint64 uNumber);
    129 
    130     /** Returns the list of the standard COM port names (i.e. "COMx"). */
    131     static QStringList COMPortNames();
    132     /** Returns the name of the standard COM port corresponding to the given parameters,
    133       * or "User-defined" (which is also returned when both @a uIRQ and @a uIOBase are 0). */
    134     static QString toCOMPortName(ulong uIRQ, ulong uIOBase);
    135     /** Returns port parameters corresponding to the given standard COM name.
    136       * Returns @c true on success, or @c false if the given port name is not one of the standard names (i.e. "COMx"). */
    137     static bool toCOMPortNumbers(const QString &strName, ulong &uIRQ, ulong &uIOBase);
    138 
    139     /** Reformats the input @a strText to highlight it. */
    140     static QString highlight(QString strText, bool fToolTip = false);
    141     /** Reformats the input @a strText to emphasize it. */
    142     static QString emphasize(QString strText);
    143     /** Removes the first occurrence of the accelerator mark (the ampersand symbol) from the given @a strText. */
    144     static QString removeAccelMark(QString strText);
    145     /** Inserts a passed @a strKey into action @a strText. */
    146     static QString insertKeyToActionText(const QString &strText, const QString &strKey);
    147 
    148     /** Returns whether we are performing translation currently. */
    149     static bool isTranslationInProgress();
    150 
    151     /* Converts bytes string to megabytes string. */
    152     static QString byteStringToMegaByteString(const QString &strByteString);
    153     /* Converts megabytes string to bytes string. */
    154     static QString megabyteStringToByteString(const QString &strMegaByteString);
    155 
    156 private:
    157 
    158     /** Constructs translator passing @a pParent to the base-class. */
    159     UITranslator(QObject *pParent = 0);
    160 
    161     /** Loads language file with gained @a strFileName. */
    162     bool loadFile(const QString &strFileName);
    163 
    164     /** Native language name of the currently installed translation. */
    165     static QString languageName();
    166     /** Native language country name of the currently installed translation. */
    167     static QString languageCountry();
    168     /** Language name of the currently installed translation, in English. */
    169     static QString languageNameEnglish();
    170     /** Language country name of the currently installed translation, in English. */
    171     static QString languageCountryEnglish();
    172     /** Comma-separated list of authors of the currently installed translation. */
    173     static QString languageTranslators();
    174 
    175     /** Returns the system language ID. */
    176     static QString systemLanguageId();
    177 
    178     /** Holds the singleton instance. */
    179     static UITranslator *s_pTranslator;
    180 
    181     /** Holds whether we are performing translation currently. */
    182     static bool  s_fTranslationInProgress;
    183 
    184     /** Holds the currently loaded language ID. */
    185     static QString  s_strLoadedLanguageId;
    186 
    187     /** Holds the loaded data. */
    188     QByteArray  m_data;
     53    bool eventFilter(QObject *pObject, QEvent *pEvent) override final;
    18954};
    19055
    191 #endif /* !FEQT_INCLUDED_SRC_globals_UITranslator_h */
    192 
     56#endif /* !FEQT_INCLUDED_SRC_globals_UITranslationEventListener_h */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette