Changeset 103914 in vbox
- Timestamp:
- Mar 19, 2024 12:08:58 PM (10 months ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 3 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r103795 r103914 836 836 src/globals/UITextTable.h \ 837 837 src/globals/UITranslator.h \ 838 src/globals/UITranslationEventListener.h \ 838 839 src/globals/UIVirtualBoxEventHandler.h \ 839 840 src/globals/UIVirtualBoxClientEventHandler.h \ … … 1414 1415 src/globals/UIThreadPool.cpp \ 1415 1416 src/globals/UITranslator.cpp \ 1417 src/globals/UITranslationEventListener.cpp \ 1416 1418 src/globals/UIVersion.cpp \ 1417 1419 src/globals/UIVirtualBoxEventHandler.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp
r103793 r103914 79 79 #include "UIThreadPool.h" 80 80 #include "UITranslator.h" 81 #include "UITranslationEventListener.h" 81 82 #include "UIVersion.h" 82 83 #include "UIVirtualBoxClientEventHandler.h" … … 223 224 , m_pThreadPoolCloud(0) 224 225 , m_pMediumEnumerator(0) 226 , m_pTranlationEventListener(0) 225 227 { 226 228 /* Assign instance: */ … … 303 305 304 306 retranslateUi(); 307 308 m_pTranlationEventListener = new UITranslationEventListener(this); 305 309 306 310 connect(gEDataManager, &UIExtraDataManager::sigLanguageChange, -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.h
r103803 r103914 62 62 class UIMediumEnumerator; 63 63 class UIThreadPool; 64 class UITranslationEventListener; 64 65 65 66 /** QObject subclass containing common GUI functionality. */ … … 680 681 /** @} */ 681 682 683 UITranslationEventListener *m_pTranlationEventListener; 682 684 /** Allows for shortcut access. */ 683 685 friend UICommon &uiCommon(); -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UITranslationEventListener.cpp
r103906 r103914 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UITranslat or class implementation.3 * VBox Qt GUI - UITranslationEventListener class implementation. 4 4 */ 5 5 … … 28 28 /* Qt includes: */ 29 29 #include <QApplication> 30 #include <QDir>31 #include <QKeySequence>32 #include <QRegularExpression>33 #ifdef Q_OS_UNIX34 # include <QLibraryInfo>35 #endif36 30 37 31 /* GUI includes: */ 38 #include "UIConverter.h" 39 #include "UIMessageCenter.h" 32 #include "UITranslationEventListener.h" 40 33 #include "UITranslator.h" 41 #ifdef VBOX_WS_MAC42 # include "VBoxUtils-darwin.h"43 #endif44 45 /* Other VBox includes: */46 #include <iprt/assert.h>47 #include <iprt/path.h>48 #ifdef Q_OS_UNIX49 # include <iprt/env.h>50 #endif51 52 /* External includes: */53 #include <math.h>54 34 55 35 56 /** Port config cache. */ 57 struct PortConfig 36 37 UITranslationEventListener::UITranslationEventListener(QObject *pParent /* = 0 */) 38 :QObject(pParent) 58 39 { 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); 244 41 } 245 42 246 /* static */ 247 QString UITranslator::vboxLanguageSubDirectory() 43 bool UITranslationEventListener::eventFilter(QObject *pObject, QEvent *pEvent) 248 44 { 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); 250 53 } 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 for282 * 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 valid284 * 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 present372 * (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 present376 * - cap(5): size suffix in case when decimal point is present (note that377 * 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 else433 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 else469 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 else500 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 the510 * closest number containing @a aDecimal decimal digits.511 * When enmMode is FormatSize_RoundDown, the result is rounded to the512 * largest number with @a aDecimal decimal digits that is not greater than513 * the result. This guarantees that converting the resulting string back to514 * the integer value in bytes will not produce a value greater that the515 * initial size parameter.516 * When enmMode is FormatSize_RoundUp, the result is rounded to the517 * smallest number with @a aDecimal decimal digits that is not less than the518 * result. This guarantees that converting the resulting string back to the519 * integer value in bytes will not produce a value less that the initial520 * 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 else551 {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 else576 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 else596 {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 the655 same prefix and suffix expression. Unfortunately, QRegularExpression isn't656 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 marked670 * with blue color;671 * - UUIDs be put inside <nobr> and marked672 * with green color;673 * - replaces new line chars with </p><p> constructs to form paragraphs674 * (note that <p\> and </p> are not appended to the beginning and to the675 * end of the string respectively, to allow the result be appended676 * or prepended to the existing paragraph).677 *678 * If @a fToolTip is true, colouring is not applied, only the <nobr> tag679 * 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('&', "&");693 strText.replace('<', "<");694 strText.replace('>', ">");695 strText.replace('\"', """);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 else707 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 marked717 * with bold style;718 * - UUIDs be put inside \<nobr\> and marked719 * with italic style;720 * - replaces new line chars with \</p\>\<p\> constructs to form paragraphs721 * (note that \<p\> and \</p\> are not appended to the beginning and to the722 * end of the string respectively, to allow the result be appended723 * 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('&', "&");732 strText.replace('<', "<");733 strText.replace('>', ">");734 strText.replace('\"', """);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 languages752 * (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 a754 * whole. If such a pattern is not found, then the '&' character is simply755 * 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 else763 {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_MAC776 QString strPattern("%1 (Host+%2)");777 #else778 QString strPattern("%1 \tHost+%2");779 #endif780 if ( strKey.isEmpty()781 || strKey.compare("None", Qt::CaseInsensitive) == 0)782 return strText;783 else784 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 installed833 * 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 file842 * 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 installed852 * 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 file861 * 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 file871 * 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 systems880 * (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_MESSAGES882 * which is designed to define a language for program messages in case if it differs from the language for883 * 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.html887 *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 format892 // 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 #endif903 return QLocale::system().name();904 } -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UITranslationEventListener.h
r103906 r103914 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UITranslat or class declaration.3 * VBox Qt GUI - UITranslationEventListener class declaration. 4 4 */ 5 5 … … 26 26 */ 27 27 28 #ifndef FEQT_INCLUDED_SRC_globals_UITranslat or_h29 #define FEQT_INCLUDED_SRC_globals_UITranslat or_h28 #ifndef FEQT_INCLUDED_SRC_globals_UITranslationEventListener_h 29 #define FEQT_INCLUDED_SRC_globals_UITranslationEventListener_h 30 30 #ifndef RT_WITHOUT_PRAGMA_ONCE 31 31 # pragma once … … 33 33 34 34 /* Qt includes: */ 35 #include <Q Translator>35 #include <QObject> 36 36 37 /* GUI includes: */38 37 #include "UILibraryDefs.h" 39 38 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 39 class SHARED_LIBRARY_STUFF UITranslationEventListener : public QObject 54 40 { 55 41 Q_OBJECT; 56 42 43 signals: 44 45 void sigRetranslate(); 46 57 47 public: 58 48 59 /** Size formatting types. */ 60 enum FormatSize 61 { 62 FormatSize_Round, 63 FormatSize_RoundDown, 64 FormatSize_RoundUp 65 }; 49 UITranslationEventListener(QObject *pParent = 0); 66 50 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()); 51 protected: 71 52 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; 189 54 }; 190 55 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.