Skip to content

Conversation

@hoffie
Copy link
Member

@hoffie hoffie commented Feb 20, 2022

Short description of changes

The country-code-to-flag-image handling has traditionally used a rather large switch/case statement to retain support for Qt4 (according to the comments). We no longer support building with Qt4.

A Qt-native approach had already been developed by @corrados, but it was disabled. This commit removes the switch-based lookup and enables the QLocale::matchingLocales-based lookup instead.

It has been verified that the new approach handles all of the previously supported codes.
The new code adds support for all codes which are available in the current Qt version and where flag icons are available. When building on Qt 5.15.2 or 6.2.3 this results in support for 53 new countries/flags compared to the old logic. IOW, we already have flag icons for 53 countries which are unusable with the current approach.
With this change, those countries become selectable in clients' user profile settings and in servers' country settings. Clients which enounter one of the new countries, but are based on the old logic will show a placeholder if they can't resolve the unknown country code.

This stems from #2299 (comment)

Context: Fixes an issue?

Related: #2299

Does this change need documentation? What needs to be documented and how?

No.
CHANGELOG: GUI: Improve Country selection handling to work with Qt6 and cover 53 previously unsupported territories.

Status of this Pull Request

Ready for review.

What is missing until this pull request can be merged?

Done.

  • All previously supported countries should still be supported.
  • Correctness of the newly supported countries' flags: All correct, but tv and tk are outdated
  • Test what an old client sees when encountering a new client with a previously unsupported country: Flag gets hidden
  • Test that an old server doesn't break when encountering a new client with a previously unsupported country: Done, old server just forwards as-is.

Checklist

  • I've verified that this Pull Request follows the general code principles
  • I tested my code and it does what I want
  • My code follows the style guide
  • I waited some time after this Pull Request was opened and all GitHub checks completed without errors.
  • I've filled all the content above

Comparison of the results of the old logic vs. the new logic

Setup

Patch main.cpp as follows to make Jamulus output a list of all country codes along with their assigned flag, human-readable name and flag load status
diff --git a/src/main.cpp b/src/main.cpp
index 3ddc8cf4..fd63af4d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,6 +24,8 @@
 
 #include <QCoreApplication>
 #include <QDir>
+#include <QLocale>
+#include <QIcon>
 #include <iostream>
 #include "global.h"
 #ifndef HEADLESS
@@ -47,6 +49,26 @@ extern void qt_set_sequence_auto_mnemonic ( bool bEnable );
 
 int main ( int argc, char** argv )
 {
+    QApplication* pAppTest = new QApplication ( argc, argv );
+    Q_UNUSED ( pAppTest );
+
+    // Iterate over all supported and one unsupported (+1) locale id:
+    for ( int iCurCntry = static_cast<int> ( QLocale::AnyCountry ); iCurCntry < static_cast<int> ( QLocale::LastCountry ) + 1; iCurCntry++ )
+    {
+        // get current country enum
+        QLocale::Country eCountry = static_cast<QLocale::Country> ( iCurCntry );
+        QString          flagPath = CLocale::GetCountryFlagIconsResourceReference ( eCountry );
+
+        // try to load icon from resource file name
+        QIcon CurFlagIcon;
+        CurFlagIcon.addFile ( flagPath );
+
+        QString loadStatus = CurFlagIcon.isNull() ? "null  " : "loaded";
+
+        qDebug() << "code =" << iCurCntry << "flagPath =" << flagPath << "loadStatus =" << loadStatus
+                 << "countryToString() =" << QLocale::countryToString ( eCountry );
+    }
+    exit ( 0 );
 
 #if defined( Q_OS_MACX )
     // Mnemonic keys are default disabled in Qt for MacOS. The following function enables them.

Generate lists for both builds

Patch, run build on master and this PR and capture the outputs
$ patch -p1 -i /tmp/patch-from-above
$ git checkout master
$ make clean; make -j
$ ./Jamulus  &> ~/tmp/flag-master-fac5d9d1e2a1321fdd53fda350a71f1d91f66b8c

$ git checkout pr2409
$ make clean; make -j
$ ./Jamulus  &> ~/tmp/flag-pr2409-9d4f71114ec7c6105c5ad8f29ed3f829142f75fa

Analysis

  • No previously supported flags are removed:
$ diff -u0 ~/tmp/flag-master-fac5d9d1e2a1321fdd53fda350a71f1d91f66b8c ~/tmp/flag-pr2409-9d4f71114ec7c6105c5ad8f29ed3f829142f75fa | grep -- -code | grep -cvF 'loadStatus = "null'
0
  • 53 previously unsupported country codes are supported by this PR:
$ diff -u0 ~/tmp/flag-master-fac5d9d1e2a1321fdd53fda350a71f1d91f66b8c ~/tmp/flag-pr2409-9d4f71114ec7c6105c5ad8f29ed3f829142f75fa | grep -c -- +code 
53
Full list
$ diff -u0 ~/tmp/flag-master-fac5d9d1e2a1321fdd53fda350a71f1d91f66b8c ~/tmp/flag-pr2409-9d4f71114ec7c6105c5ad8f29ed3f829142f75fa | grep  -- +code 
+code = 4 flagPath = ":/png/flags/res/flags/as.png" loadStatus = "loaded" countryToString() = "American Samoa"
+code = 7 flagPath = ":/png/flags/res/flags/ai.png" loadStatus = "loaded" countryToString() = "Anguilla"
+code = 9 flagPath = ":/png/flags/res/flags/ag.png" loadStatus = "loaded" countryToString() = "Antigua And Barbuda"
+code = 16 flagPath = ":/png/flags/res/flags/bs.png" loadStatus = "loaded" countryToString() = "Bahamas"
+code = 19 flagPath = ":/png/flags/res/flags/bb.png" loadStatus = "loaded" countryToString() = "Barbados"
+code = 22 flagPath = ":/png/flags/res/flags/bz.png" loadStatus = "loaded" countryToString() = "Belize"
+code = 24 flagPath = ":/png/flags/res/flags/bm.png" loadStatus = "loaded" countryToString() = "Bermuda"
+code = 31 flagPath = ":/png/flags/res/flags/io.png" loadStatus = "loaded" countryToString() = "British Indian Ocean Territory"
+code = 40 flagPath = ":/png/flags/res/flags/ky.png" loadStatus = "loaded" countryToString() = "Cayman Islands"
+code = 45 flagPath = ":/png/flags/res/flags/cx.png" loadStatus = "loaded" countryToString() = "Christmas Island"
+code = 46 flagPath = ":/png/flags/res/flags/cc.png" loadStatus = "loaded" countryToString() = "Cocos Islands"
+code = 51 flagPath = ":/png/flags/res/flags/ck.png" loadStatus = "loaded" countryToString() = "Cook Islands"
+code = 60 flagPath = ":/png/flags/res/flags/dm.png" loadStatus = "loaded" countryToString() = "Dominica"
+code = 70 flagPath = ":/png/flags/res/flags/fk.png" loadStatus = "loaded" countryToString() = "Falkland Islands"
+code = 72 flagPath = ":/png/flags/res/flags/fj.png" loadStatus = "loaded" countryToString() = "Fiji"
+code = 80 flagPath = ":/png/flags/res/flags/gm.png" loadStatus = "loaded" countryToString() = "Gambia"
+code = 84 flagPath = ":/png/flags/res/flags/gi.png" loadStatus = "loaded" countryToString() = "Gibraltar"
+code = 87 flagPath = ":/png/flags/res/flags/gd.png" loadStatus = "loaded" countryToString() = "Grenada"
+code = 89 flagPath = ":/png/flags/res/flags/gu.png" loadStatus = "loaded" countryToString() = "Guam"
+code = 94 flagPath = ":/png/flags/res/flags/ht.png" loadStatus = "loaded" countryToString() = "Haiti"
+code = 107 flagPath = ":/png/flags/res/flags/jm.png" loadStatus = "loaded" countryToString() = "Jamaica"
+code = 112 flagPath = ":/png/flags/res/flags/ki.png" loadStatus = "loaded" countryToString() = "Kiribati"
+code = 121 flagPath = ":/png/flags/res/flags/lr.png" loadStatus = "loaded" countryToString() = "Liberia"
+code = 129 flagPath = ":/png/flags/res/flags/mw.png" loadStatus = "loaded" countryToString() = "Malawi"
+code = 131 flagPath = ":/png/flags/res/flags/mv.png" loadStatus = "loaded" countryToString() = "Maldives"
+code = 134 flagPath = ":/png/flags/res/flags/mh.png" loadStatus = "loaded" countryToString() = "Marshall Islands"
+code = 140 flagPath = ":/png/flags/res/flags/fm.png" loadStatus = "loaded" countryToString() = "Micronesia"
+code = 144 flagPath = ":/png/flags/res/flags/ms.png" loadStatus = "loaded" countryToString() = "Montserrat"
+code = 149 flagPath = ":/png/flags/res/flags/nr.png" loadStatus = "loaded" countryToString() = "Nauru"
+code = 158 flagPath = ":/png/flags/res/flags/nu.png" loadStatus = "loaded" countryToString() = "Niue"
+code = 159 flagPath = ":/png/flags/res/flags/nf.png" loadStatus = "loaded" countryToString() = "Norfolk Island"
+code = 160 flagPath = ":/png/flags/res/flags/mp.png" loadStatus = "loaded" countryToString() = "Northern Mariana Islands"
+code = 164 flagPath = ":/png/flags/res/flags/pw.png" loadStatus = "loaded" countryToString() = "Palau"
+code = 171 flagPath = ":/png/flags/res/flags/pn.png" loadStatus = "loaded" countryToString() = "Pitcairn"
+code = 180 flagPath = ":/png/flags/res/flags/kn.png" loadStatus = "loaded" countryToString() = "Saint Kitts And Nevis"
+code = 181 flagPath = ":/png/flags/res/flags/lc.png" loadStatus = "loaded" countryToString() = "Saint Lucia"
+code = 182 flagPath = ":/png/flags/res/flags/vc.png" loadStatus = "loaded" countryToString() = "Saint Vincent And The Grenadines"
+code = 183 flagPath = ":/png/flags/res/flags/ws.png" loadStatus = "loaded" countryToString() = "Samoa"
+code = 193 flagPath = ":/png/flags/res/flags/sb.png" loadStatus = "loaded" countryToString() = "Solomon Islands"
+code = 199 flagPath = ":/png/flags/res/flags/sh.png" loadStatus = "loaded" countryToString() = "Saint Helena"
+code = 200 flagPath = ":/png/flags/res/flags/pm.png" loadStatus = "loaded" countryToString() = "Saint Pierre And Miquelon"
+code = 203 flagPath = ":/png/flags/res/flags/sj.png" loadStatus = "loaded" countryToString() = "Svalbard And Jan Mayen Islands"
+code = 213 flagPath = ":/png/flags/res/flags/tk.png" loadStatus = "loaded" countryToString() = "Tokelau"
+code = 215 flagPath = ":/png/flags/res/flags/tt.png" loadStatus = "loaded" countryToString() = "Trinidad And Tobago"
+code = 218 flagPath = ":/png/flags/res/flags/tm.png" loadStatus = "loaded" countryToString() = "Turkmenistan"
+code = 219 flagPath = ":/png/flags/res/flags/tc.png" loadStatus = "loaded" countryToString() = "Turks And Caicos Islands"
+code = 220 flagPath = ":/png/flags/res/flags/tv.png" loadStatus = "loaded" countryToString() = "Tuvalu"
+code = 226 flagPath = ":/png/flags/res/flags/um.png" loadStatus = "loaded" countryToString() = "United States Minor Outlying Islands"
+code = 229 flagPath = ":/png/flags/res/flags/vu.png" loadStatus = "loaded" countryToString() = "Vanuatu"
+code = 230 flagPath = ":/png/flags/res/flags/va.png" loadStatus = "loaded" countryToString() = "Vatican City State"
+code = 233 flagPath = ":/png/flags/res/flags/vg.png" loadStatus = "loaded" countryToString() = "British Virgin Islands"
+code = 234 flagPath = ":/png/flags/res/flags/vi.png" loadStatus = "loaded" countryToString() = "United States Virgin Islands"
+code = 235 flagPath = ":/png/flags/res/flags/wf.png" loadStatus = "loaded" countryToString() = "Wallis And Futuna Islands"

  • No two country codes reference the same flag:
grep -F .png ~/tmp/flag-pr2409-9d4f71114ec7c6105c5ad8f29ed3f829142f75fa | cut -d/ -f6 | cut -d'"' -f1 | sort | uniq -c | grep -cv ' 1 ' 
0

hoffie and others added 2 commits February 13, 2022 17:21
The country-code-to-flag-image handling has traditionally used a rather
large switch/case statement to retain support for Qt4 (according to the
comments). We no longer support building with Qt4.

A Qt-native approach had already been developed by @corrados, but it was
disabled. This commit removes the switch-based lookup and enables the
QLocale::matchingLocales-based lookup instead.

It has been verified that the new approach handles all of the
previously supported codes.
The new code adds support for all codes which are available in the
current Qt version and where flag icons are available. When building on
Qt 5.15.2 or 6.2.3 this results in support for 53 new countries/flags
compared to the old logic. Those countries become selectable in clients'
user profile settings and in servers' country settings.
Clients which are based on the old logic will show a placeholder if they
can't resolve an unknown country code.

Co-authored-by: Volker Fischer <corrados@users.noreply.github.com>
@hoffie hoffie added this to the Release 3.9.0 milestone Feb 20, 2022
@hoffie hoffie marked this pull request as draft February 20, 2022 00:09
@hoffie hoffie mentioned this pull request Feb 20, 2022
11 tasks
@hoffie
Copy link
Member Author

hoffie commented Feb 26, 2022

Current status of this PR: I assume the code is done, but I still have to re-run some tests and aggregate the results. That's why I've left it in Draft status for now.

@hoffie
Copy link
Member Author

hoffie commented Feb 27, 2022

Another update: I have added the before/after test to the PR description and everything looks good, so I'd say the PR is ready for further reviews.
I still want to do some additional tests (see unchecked TOOOs in the PR description), but I'm not expecting any code changes right now and want to do them just to be extra safe. Therefore, we should not merge yet and I'm keeping Draft status for now.

@hoffie
Copy link
Member Author

hoffie commented Feb 27, 2022

I've checked all newly supported flags and compared them with https://en.wikipedia.org/wiki/Country_code_top-level_domain
All looked similar, except two: "tk" and "tv". Both seem to use a historical flag in Jamulus' icon set and should probably be updated. The original author does not have new flags for them (just checked).
I'd tend to keep them as-is and will open an issue to find a way to update those. See #2439.

@hoffie
Copy link
Member Author

hoffie commented Feb 27, 2022

All further tests (old client vs. new client vs. old server vs. new server) were successful and did not show any issues. Therefore removing Draft status. Can be merged after another review.

@hoffie hoffie marked this pull request as ready for review February 27, 2022 14:07
@hoffie hoffie requested a review from softins February 27, 2022 14:07
Copy link
Member

@softins softins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well the code looks ok, so I'll approve it. I've built it on my Pi with Qt 5.15.2, and can see the extra territories.

But reading the comments around #2299 (comment), I'm still wondering about the compatibility between Qt5 and Qt6 versions of Jamulus with respect to the country value on the wire in the Jamulus protocol. Do we need a compatibility layer that defines the country codes on the wire and in --serverinfo independently of Qt? (Although they would in fact be the same as the Qt5 numbers).

@hoffie
Copy link
Member Author

hoffie commented Feb 27, 2022

Well the code looks ok, so I'll approve it. I've built it on my Pi with Qt 5.15.2, and can see the extra territories.

Thanks!

But reading the comments around #2299 (comment), I'm still wondering about the compatibility between Qt5 and Qt6 versions of Jamulus with respect to the country value on the wire in the Jamulus protocol. Do we need a compatibility layer that defines the country codes on the wire and in --serverinfo independently of Qt? (Although they would in fact be the same as the Qt5 numbers).

Yes, we do need that and that's part of #2299. This PR (#2409) only splits out one part (replacement of the flag handling) as it's rather large (code-wise) and simplifies the work in #2299.

@hoffie hoffie merged commit 74150e5 into jamulussoftware:master Feb 27, 2022
@hoffie hoffie deleted the flag-clocale-matchingLocales branch March 19, 2022 21:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants