1 /******************************************************************************\
2  * Copyright (c) 2004-2020
3  *
4  * Author(s):
5  *  Volker Fischer
6  *
7  ******************************************************************************
8  *
9  * This program is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License as published by the Free Software
11  * Foundation; either version 2 of the License, or (at your option) any later
12  * version.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
22  *
23 \******************************************************************************/
24 
25 #include "util.h"
26 #include "client.h"
27 
28 /* Implementation *************************************************************/
29 // Input level meter implementation --------------------------------------------
Update(const CVector<short> & vecsAudio,const int iMonoBlockSizeSam,const bool bIsStereoIn)30 void CStereoSignalLevelMeter::Update ( const CVector<short>& vecsAudio, const int iMonoBlockSizeSam, const bool bIsStereoIn )
31 {
32     // Get maximum of current block
33     //
34     // Speed optimization:
35     // - we only make use of the negative values and ignore the positive ones (since
36     //   int16 has range {-32768, 32767}) -> we do not need to call the fabs() function
37     // - we only evaluate every third sample
38     //
39     // With these speed optimizations we might loose some information in
40     // special cases but for the average music signals the following code
41     // should give good results.
42     short sMinLOrMono = 0;
43     short sMinR       = 0;
44 
45     if ( bIsStereoIn )
46     {
47         // stereo in
48         for ( int i = 0; i < 2 * iMonoBlockSizeSam; i += 6 ) // 2 * 3 = 6 -> stereo
49         {
50             // left (or mono) and right channel
51             sMinLOrMono = std::min ( sMinLOrMono, vecsAudio[i] );
52             sMinR       = std::min ( sMinR, vecsAudio[i + 1] );
53         }
54 
55         // in case of mono out use minimum of both channels
56         if ( !bIsStereoOut )
57         {
58             sMinLOrMono = std::min ( sMinLOrMono, sMinR );
59         }
60     }
61     else
62     {
63         // mono in
64         for ( int i = 0; i < iMonoBlockSizeSam; i += 3 )
65         {
66             sMinLOrMono = std::min ( sMinLOrMono, vecsAudio[i] );
67         }
68     }
69 
70     // apply smoothing, if in stereo out mode, do this for two channels
71     dCurLevelLOrMono = UpdateCurLevel ( dCurLevelLOrMono, -sMinLOrMono );
72 
73     if ( bIsStereoOut )
74     {
75         dCurLevelR = UpdateCurLevel ( dCurLevelR, -sMinR );
76     }
77 }
78 
UpdateCurLevel(double dCurLevel,const double dMax)79 double CStereoSignalLevelMeter::UpdateCurLevel ( double dCurLevel, const double dMax )
80 {
81     // decrease max with time
82     if ( dCurLevel >= METER_FLY_BACK )
83     {
84         dCurLevel *= dSmoothingFactor;
85     }
86     else
87     {
88         dCurLevel = 0;
89     }
90 
91     // update current level -> only use maximum
92     if ( dMax > dCurLevel )
93     {
94         return dMax;
95     }
96     else
97     {
98         return dCurLevel;
99     }
100 }
101 
CalcLogResultForMeter(const double & dLinearLevel)102 double CStereoSignalLevelMeter::CalcLogResultForMeter ( const double& dLinearLevel )
103 {
104     const double dNormLevel = dLinearLevel / _MAXSHORT;
105 
106     // logarithmic measure
107     double dLevelForMeterdB = -100000.0; // large negative value
108 
109     if ( dNormLevel > 0 )
110     {
111         dLevelForMeterdB = 20.0 * log10 ( dNormLevel );
112     }
113 
114     // map to signal level meter (linear transformation of the input
115     // level range to the level meter range)
116     dLevelForMeterdB -= LOW_BOUND_SIG_METER;
117     dLevelForMeterdB *= NUM_STEPS_LED_BAR / ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
118 
119     if ( dLevelForMeterdB < 0 )
120     {
121         dLevelForMeterdB = 0;
122     }
123 
124     return dLevelForMeterdB;
125 }
126 
127 // CRC -------------------------------------------------------------------------
Reset()128 void CCRC::Reset()
129 {
130     // init state shift-register with ones. Set all registers to "1" with
131     // bit-wise not operation
132     iStateShiftReg = ~uint32_t ( 0 );
133 }
134 
AddByte(const uint8_t byNewInput)135 void CCRC::AddByte ( const uint8_t byNewInput )
136 {
137     for ( int i = 0; i < 8; i++ )
138     {
139         // shift bits in shift-register for transition
140         iStateShiftReg <<= 1;
141 
142         // take bit, which was shifted out of the register-size and place it
143         // at the beginning (LSB)
144         // (If condition is not satisfied, implicitly a "0" is added)
145         if ( ( iStateShiftReg & iBitOutMask ) > 0 )
146         {
147             iStateShiftReg |= 1;
148         }
149 
150         // add new data bit to the LSB
151         if ( ( byNewInput & ( 1 << ( 8 - i - 1 ) ) ) > 0 )
152         {
153             iStateShiftReg ^= 1;
154         }
155 
156         // add mask to shift-register if first bit is true
157         if ( iStateShiftReg & 1 )
158         {
159             iStateShiftReg ^= iPoly;
160         }
161     }
162 }
163 
GetCRC()164 uint32_t CCRC::GetCRC()
165 {
166     // return inverted shift-register (1's complement)
167     iStateShiftReg = ~iStateShiftReg;
168 
169     // remove bit which where shifted out of the shift-register frame
170     return iStateShiftReg & ( iBitOutMask - 1 );
171 }
172 
173 /******************************************************************************\
174 * Audio Reverberation                                                          *
175 \******************************************************************************/
176 /*
177     The following code is based on "JCRev: John Chowning's reverberator class"
178     by Perry R. Cook and Gary P. Scavone, 1995 - 2004
179     which is in "The Synthesis ToolKit in C++ (STK)"
180     http://ccrma.stanford.edu/software/stk
181 
182     Original description:
183     This class is derived from the CLM JCRev function, which is based on the use
184     of networks of simple allpass and comb delay filters. This class implements
185     three series allpass units, followed by four parallel comb filters, and two
186     decorrelation delay lines in parallel at the output.
187 */
Init(const EAudChanConf eNAudioChannelConf,const int iNStereoBlockSizeSam,const int iSampleRate,const float fT60)188 void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam, const int iSampleRate, const float fT60 )
189 {
190     // store parameters
191     eAudioChannelConf   = eNAudioChannelConf;
192     iStereoBlockSizeSam = iNStereoBlockSizeSam;
193 
194     // delay lengths for 44100 Hz sample rate
195     int         lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
196     const float scaler     = static_cast<float> ( iSampleRate ) / 44100.0f;
197 
198     if ( scaler != 1.0f )
199     {
200         for ( int i = 0; i < 9; i++ )
201         {
202             int delay = static_cast<int> ( floorf ( scaler * lengths[i] ) );
203 
204             if ( ( delay & 1 ) == 0 )
205             {
206                 delay++;
207             }
208 
209             while ( !isPrime ( delay ) )
210             {
211                 delay += 2;
212             }
213 
214             lengths[i] = delay;
215         }
216     }
217 
218     for ( int i = 0; i < 3; i++ )
219     {
220         allpassDelays[i].Init ( lengths[i + 4] );
221     }
222 
223     for ( int i = 0; i < 4; i++ )
224     {
225         combDelays[i].Init ( lengths[i] );
226         combFilters[i].setPole ( 0.2f );
227     }
228 
229     setT60 ( fT60, iSampleRate );
230     outLeftDelay.Init ( lengths[7] );
231     outRightDelay.Init ( lengths[8] );
232     allpassCoefficient = 0.7f;
233     Clear();
234 }
235 
isPrime(const int number)236 bool CAudioReverb::isPrime ( const int number )
237 {
238     /*
239         Returns true if argument value is prime. Taken from "class Effect" in
240         "STK abstract effects parent class".
241     */
242     if ( number == 2 )
243     {
244         return true;
245     }
246 
247     if ( number & 1 )
248     {
249         for ( int i = 3; i < static_cast<int> ( sqrtf ( static_cast<float> ( number ) ) ) + 1; i += 2 )
250         {
251             if ( ( number % i ) == 0 )
252             {
253                 return false;
254             }
255         }
256 
257         return true; // prime
258     }
259     else
260     {
261         return false; // even
262     }
263 }
264 
Clear()265 void CAudioReverb::Clear()
266 {
267     // reset and clear all internal state
268     allpassDelays[0].Reset ( 0 );
269     allpassDelays[1].Reset ( 0 );
270     allpassDelays[2].Reset ( 0 );
271     combDelays[0].Reset ( 0 );
272     combDelays[1].Reset ( 0 );
273     combDelays[2].Reset ( 0 );
274     combDelays[3].Reset ( 0 );
275     combFilters[0].Reset();
276     combFilters[1].Reset();
277     combFilters[2].Reset();
278     combFilters[3].Reset();
279     outRightDelay.Reset ( 0 );
280     outLeftDelay.Reset ( 0 );
281 }
282 
setT60(const float fT60,const int iSampleRate)283 void CAudioReverb::setT60 ( const float fT60, const int iSampleRate )
284 {
285     // set the reverberation T60 decay time
286     for ( int i = 0; i < 4; i++ )
287     {
288         combCoefficient[i] = powf ( 10.0f, static_cast<float> ( -3.0f * combDelays[i].Size() / ( fT60 * iSampleRate ) ) );
289     }
290 }
291 
setPole(const float fPole)292 void CAudioReverb::COnePole::setPole ( const float fPole )
293 {
294     // calculate IIR filter coefficients based on the pole value
295     fA = -fPole;
296     fB = 1.0f - fPole;
297 }
298 
Calc(const float fIn)299 float CAudioReverb::COnePole::Calc ( const float fIn )
300 {
301     // calculate IIR filter
302     fLastSample = fB * fIn - fA * fLastSample;
303 
304     return fLastSample;
305 }
306 
Process(CVector<int16_t> & vecsStereoInOut,const bool bReverbOnLeftChan,const float fAttenuation)307 void CAudioReverb::Process ( CVector<int16_t>& vecsStereoInOut, const bool bReverbOnLeftChan, const float fAttenuation )
308 {
309     float fMixedInput, temp, temp0, temp1, temp2;
310 
311     for ( int i = 0; i < iStereoBlockSizeSam; i += 2 )
312     {
313         // we sum up the stereo input channels (in case mono input is used, a zero
314         // shall be input for the right channel)
315         if ( eAudioChannelConf == CC_STEREO )
316         {
317             fMixedInput = 0.5f * ( vecsStereoInOut[i] + vecsStereoInOut[i + 1] );
318         }
319         else
320         {
321             if ( bReverbOnLeftChan )
322             {
323                 fMixedInput = vecsStereoInOut[i];
324             }
325             else
326             {
327                 fMixedInput = vecsStereoInOut[i + 1];
328             }
329         }
330 
331         temp  = allpassDelays[0].Get();
332         temp0 = allpassCoefficient * temp;
333         temp0 += fMixedInput;
334         allpassDelays[0].Add ( temp0 );
335         temp0 = -( allpassCoefficient * temp0 ) + temp;
336 
337         temp  = allpassDelays[1].Get();
338         temp1 = allpassCoefficient * temp;
339         temp1 += temp0;
340         allpassDelays[1].Add ( temp1 );
341         temp1 = -( allpassCoefficient * temp1 ) + temp;
342 
343         temp  = allpassDelays[2].Get();
344         temp2 = allpassCoefficient * temp;
345         temp2 += temp1;
346         allpassDelays[2].Add ( temp2 );
347         temp2 = -( allpassCoefficient * temp2 ) + temp;
348 
349         const float temp3 = temp2 + combFilters[0].Calc ( combCoefficient[0] * combDelays[0].Get() );
350         const float temp4 = temp2 + combFilters[1].Calc ( combCoefficient[1] * combDelays[1].Get() );
351         const float temp5 = temp2 + combFilters[2].Calc ( combCoefficient[2] * combDelays[2].Get() );
352         const float temp6 = temp2 + combFilters[3].Calc ( combCoefficient[3] * combDelays[3].Get() );
353 
354         combDelays[0].Add ( temp3 );
355         combDelays[1].Add ( temp4 );
356         combDelays[2].Add ( temp5 );
357         combDelays[3].Add ( temp6 );
358 
359         const float filtout = temp3 + temp4 + temp5 + temp6;
360 
361         outLeftDelay.Add ( filtout );
362         outRightDelay.Add ( filtout );
363 
364         // inplace apply the attenuated reverb signal (for stereo always apply
365         // reverberation effect on both channels)
366         if ( ( eAudioChannelConf == CC_STEREO ) || bReverbOnLeftChan )
367         {
368             vecsStereoInOut[i] = Float2Short ( ( 1.0f - fAttenuation ) * vecsStereoInOut[i] + 0.5f * fAttenuation * outLeftDelay.Get() );
369         }
370 
371         if ( ( eAudioChannelConf == CC_STEREO ) || !bReverbOnLeftChan )
372         {
373             vecsStereoInOut[i + 1] = Float2Short ( ( 1.0f - fAttenuation ) * vecsStereoInOut[i + 1] + 0.5f * fAttenuation * outRightDelay.Get() );
374         }
375     }
376 }
377 
378 /******************************************************************************\
379 * GUI Utilities                                                                *
380 \******************************************************************************/
381 // About dialog ----------------------------------------------------------------
382 #ifndef HEADLESS
CAboutDlg(QWidget * parent)383 CAboutDlg::CAboutDlg ( QWidget* parent ) : CBaseDlg ( parent )
384 {
385     setupUi ( this );
386 
387     // general description of software
388     txvAbout->setText ( "<p>" +
389                         tr ( "This app enables musicians to perform real-time jam sessions "
390                              "over the internet." ) +
391                         "<br>" +
392                         tr ( "There is a server which collects "
393                              " the audio data from each client, mixes the audio data and sends the mix "
394                              " back to each client." ) +
395                         "</p>"
396                         "<p><font face=\"courier\">" // GPL header text
397                         "This program is free software; you can redistribute it and/or modify "
398                         "it under the terms of the GNU General Public License as published by "
399                         "the Free Software Foundation; either version 2 of the License, or "
400                         "(at your option) any later version.<br>This program is distributed in "
401                         "the hope that it will be useful, but WITHOUT ANY WARRANTY; without "
402                         "even the implied warranty of MERCHANTABILITY or FITNESS FOR A "
403                         "PARTICULAR PURPOSE. See the GNU General Public License for more "
404                         "details.<br>You should have received a copy of the GNU General Public "
405                         "License along with his program; if not, write to the Free Software "
406                         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 "
407                         "USA"
408                         "</font></p>" );
409 
410     // libraries used by this compilation
411     txvLibraries->setText (
412         tr ( "This app uses the following libraries, resources or code snippets:" ) + "<br><p>" + tr ( "Qt cross-platform application framework" ) +
413         ", <i><a href=\"http://www.qt.io\">http://www.qt.io</a></i></p>"
414         "<p>Opus Interactive Audio Codec"
415         ", <i><a href=\"http://www.opus-codec.org\">http://www.opus-codec.org</a></i></p>"
416         "<p>" +
417         tr ( "Audio reverberation code by Perry R. Cook and Gary P. Scavone" ) +
418         ", 1995 - 2004, <i><a href=\"http://ccrma.stanford.edu/software/stk\">"
419         "The Synthesis ToolKit in C++ (STK)</a></i></p>"
420         "<p>" +
421         tr ( "Some pixmaps are from the" ) +
422         " Open Clip Art Library (OCAL), "
423         "<i><a href=\"http://openclipart.org\">http://openclipart.org</a></i></p>"
424         "<p>" +
425         tr ( "Country flag icons by Mark James" ) + ", <i><a href=\"http://www.famfamfam.com\">http://www.famfamfam.com</a></i></p>" );
426 
427     // contributors list
428     txvContributors->setText ( "<p>Volker Fischer (<a href=\"https://github.com/corrados\">corrados</a>)</p>"
429                                "<p>Peter L. Jones (<a href=\"https://github.com/pljones\">pljones</a>)</p>"
430                                "<p>Jonathan Baker-Bates (<a href=\"https://github.com/gilgongo\">gilgongo</a>)</p>"
431                                "<p>ann0see (<a href=\"https://github.com/ann0see\">ann0see</a>)</p>"
432                                "<p>Daniele Masato (<a href=\"https://github.com/doloopuntil\">doloopuntil</a>)</p>"
433                                "<p>Martin Schilde (<a href=\"https://github.com/geheimerEichkater\">geheimerEichkater</a>)</p>"
434                                "<p>Simon Tomlinson (<a href=\"https://github.com/sthenos\">sthenos</a>)</p>"
435                                "<p>Marc jr. Landolt (<a href=\"https://github.com/braindef\">braindef</a>)</p>"
436                                "<p>Olivier Humbert (<a href=\"https://github.com/trebmuh\">trebmuh</a>)</p>"
437                                "<p>Tarmo Johannes (<a href=\"https://github.com/tarmoj\">tarmoj</a>)</p>"
438                                "<p>mirabilos (<a href=\"https://github.com/mirabilos\">mirabilos</a>)</p>"
439                                "<p>Hector Martin (<a href=\"https://github.com/marcan\">marcan</a>)</p>"
440                                "<p>newlaurent62 (<a href=\"https://github.com/newlaurent62\">newlaurent62</a>)</p>"
441                                "<p>AronVietti (<a href=\"https://github.com/AronVietti\">AronVietti</a>)</p>"
442                                "<p>Emlyn Bolton (<a href=\"https://github.com/emlynmac\">emlynmac</a>)</p>"
443                                "<p>Jos van den Oever (<a href=\"https://github.com/vandenoever\">vandenoever</a>)</p>"
444                                "<p>Tormod Volden (<a href=\"https://github.com/tormodvolden\">tormodvolden</a>)</p>"
445                                "<p>Alberstein8 (<a href=\"https://github.com/Alberstein8\">Alberstein8</a>)</p>"
446                                "<p>Gauthier Fleutot Östervall (<a href=\"https://github.com/fleutot\">fleutot</a>)</p>"
447                                "<p>Tony Mountifield (<a href=\"https://github.com/softins\">softins</a>)</p>"
448                                "<p>HPS (<a href=\"https://github.com/hselasky\">hselasky</a>)</p>"
449                                "<p>Stanislas Michalak (<a href=\"https://github.com/stanislas-m\">stanislas-m</a>)</p>"
450                                "<p>JP Cimalando (<a href=\"https://github.com/jpcima\">jpcima</a>)</p>"
451                                "<p>Adam Sampson (<a href=\"https://github.com/atsampson\">atsampson</a>)</p>"
452                                "<p>Jakob Jarmar (<a href=\"https://github.com/jarmar\">jarmar</a>)</p>"
453                                "<p>Stefan Weil (<a href=\"https://github.com/stweil\">stweil</a>)</p>"
454                                "<p>Nils Brederlow (<a href=\"https://github.com/dingodoppelt\">dingodoppelt</a>)</p>"
455                                "<p>Sebastian Krzyszkowiak (<a href=\"https://github.com/dos1\">dos1</a>)</p>"
456                                "<p>Bryan Flamig (<a href=\"https://github.com/bflamig\">bflamig</a>)</p>"
457                                "<p>Kris Raney (<a href=\"https://github.com/kraney\">kraney</a>)</p>"
458                                "<p>dszgit (<a href=\"https://github.com/dszgit\">dszgit</a>)</p>"
459                                "<p>nefarius2001 (<a href=\"https://github.com/nefarius2001\">nefarius2001</a>)</p>"
460                                "<p>jc-Rosichini (<a href=\"https://github.com/jc-Rosichini\">jc-Rosichini</a>)</p>"
461                                "<p>Julian Santander (<a href=\"https://github.com/j-santander\">j-santander</a>)</p>"
462                                "<p>chigkim (<a href=\"https://github.com/chigkim\">chigkim</a>)</p>"
463                                "<p>Bodo (<a href=\"https://github.com/bomm\">bomm</a>)</p>"
464                                "<p>Christian Hoffmann (<a href=\"https://github.com/hoffie\">hoffie</a>)</p>"
465                                "<p>jp8 (<a href=\"https://github.com/jp8\">jp8</a>)</p>"
466                                "<p>James (<a href=\"https://github.com/jdrage\">jdrage</a>)</p>"
467                                "<p>ranfdev (<a href=\"https://github.com/ranfdev\">ranfdev</a>)</p>"
468                                "<p>bspeer (<a href=\"https://github.com/bspeer\">bspeer</a>)</p>"
469                                "<p>Martin Passing (<a href=\"https://github.com/passing\">passing</a>)</p>"
470                                "<p>DonC (<a href=\"https://github.com/dcorson-ticino-com\">dcorson-ticino-com</a>)</p>"
471                                "<p>David Kastrup (<a href=\"https://github.com/dakhubgit\">dakhubgit</a>)</p>"
472                                "<p>Jordan Lum (<a href=\"https://github.com/mulyaj\">mulyaj</a>)</p>"
473                                "<p>Noam Postavsky (<a href=\"https://github.com/npostavs\">npostavs</a>)</p>"
474                                "<p>David Savinkoff (<a href=\"https://github.com/DavidSavinkoff\">DavidSavinkoff</a>)</p>"
475                                "<p>Johannes Brauers (<a href=\"https://github.com/JohannesBrx\">JohannesBrx</a>)</p>"
476                                "<p>Henk De Groot (<a href=\"https://github.com/henkdegroot\">henkdegroot</a>)</p>"
477                                "<p>Ferenc Wágner (<a href=\"https://github.com/wferi\">wferi</a>)</p>"
478                                "<p>Martin Kaistra (<a href=\"https://github.com/djfun\">djfun</a>)</p>"
479                                "<p>Burkhard Volkemer (<a href=\"https://github.com/buv\">buv</a>)</p>"
480                                "<p>Magnus Groß (<a href=\"https://github.com/vimpostor\">vimpostor</a>)</p>"
481                                "<p>Julien Taverna (<a href=\"https://github.com/jujudusud\">jujudusud</a>)</p>"
482                                "<p>Detlef Hennings (<a href=\"https://github.com/DetlefHennings\">DetlefHennings</a>)</p>"
483                                "<p>drummer1154 (<a href=\"https://github.com/drummer1154\">drummer1154</a>)</p>"
484                                "<p>helgeerbe (<a href=\"https://github.com/helgeerbe\">helgeerbe</a>)</p>"
485                                "<p>Hk1020 (<a href=\"https://github.com/Hk1020\">Hk1020</a>)</p>"
486                                "<p>Jeroen van Veldhuizen (<a href=\"https://github.com/jeroenvv\">jeroenvv</a>)</p>"
487                                "<p>Reinhard (<a href=\"https://github.com/reinhardwh\">reinhardwh</a>)</p>"
488                                "<p>Stefan Menzel (<a href=\"https://github.com/menzels\">menzels</a>)</p>"
489                                "<p>Dau Huy Ngoc (<a href=\"https://github.com/ngocdh\">ngocdh</a>)</p>"
490                                "<p>Jiri Popek (<a href=\"https://github.com/jardous\">jardous</a>)</p>"
491                                "<p>Gary Wang (<a href=\"https://github.com/BLumia\">BLumia</a>)</p>"
492                                "<br>" +
493                                tr ( "For details on the contributions check out the " ) +
494                                "<a href=\"https://github.com/jamulussoftware/jamulus/graphs/contributors\">" + tr ( "Github Contributors list" ) +
495                                "</a>." );
496 
497     // translators
498     txvTranslation->setText ( "<p><b>" + tr ( "Spanish" ) +
499                               "</b></p>"
500                               "<p>Daryl Hanlon (<a href=\"https://github.com/ignotus666\">ignotus666</a>)</p>"
501                               "<p><b>" +
502                               tr ( "French" ) +
503                               "</b></p>"
504                               "<p>Olivier Humbert (<a href=\"https://github.com/trebmuh\">trebmuh</a>)</p>"
505                               "<p>Julien Taverna (<a href=\"https://github.com/jujudusud\">jujudusud</a>)</p>"
506                               "<p><b>" +
507                               tr ( "Portuguese" ) +
508                               "</b></p>"
509                               "<p>Miguel de Matos (<a href=\"https://github.com/Snayler\">Snayler</a>)</p>"
510                               "<p>Melcon Moraes (<a href=\"https://github.com/melcon\">melcon</a>)</p>"
511                               "<p><b>" +
512                               tr ( "Dutch" ) +
513                               "</b></p>"
514                               "<p>Jeroen Geertzen (<a href=\"https://github.com/jerogee\">jerogee</a>)</p>"
515                               "<p>Henk De Groot (<a href=\"https://github.com/henkdegroot\">henkdegroot</a>)</p>"
516                               "<p><b>" +
517                               tr ( "Italian" ) +
518                               "</b></p>"
519                               "<p>Giuseppe Sapienza (<a href=\"https://github.com/dzpex\">dzpex</a>)</p>"
520                               "<p><b>" +
521                               tr ( "German" ) +
522                               "</b></p>"
523                               "<p>Volker Fischer (<a href=\"https://github.com/corrados\">corrados</a>)</p>"
524                               "<p>Roland Moschel (<a href=\"https://github.com/rolamos\">rolamos</a>)</p>"
525                               "<p><b>" +
526                               tr ( "Polish" ) +
527                               "</b></p>"
528                               "<p>Martyna Danysz (<a href=\"https://github.com/Martyna27\">Martyna27</a>)</p>"
529                               "<p>Tomasz Bojczuk (<a href=\"https://github.com/SeeLook\">SeeLook</a>)</p>"
530                               "<p><b>" +
531                               tr ( "Swedish" ) +
532                               "</b></p>"
533                               "<p>Daniel (<a href=\"https://github.com/genesisproject2020\">genesisproject2020</a>)</p>"
534                               "<p><b>" +
535                               tr ( "Slovak" ) +
536                               "</b></p>"
537                               "<p>Jose Riha (<a href=\"https://github.com/jose1711\">jose1711</a>)</p>" +
538                               "<p><b>" + tr ( "Simplified Chinese" ) +
539                               "</b></p>"
540                               "<p>Gary Wang (<a href=\"https://github.com/BLumia\">BLumia</a>)</p>" );
541 
542     // set version number in about dialog
543     lblVersion->setText ( GetVersionAndNameStr() );
544 
545     // set window title
546     setWindowTitle ( tr ( "About " ) + APP_NAME );
547 }
548 
549 // Licence dialog --------------------------------------------------------------
CLicenceDlg(QWidget * parent)550 CLicenceDlg::CLicenceDlg ( QWidget* parent ) : CBaseDlg ( parent )
551 {
552     /*
553         The licence dialog is structured as follows:
554         - text box with the licence text on the top
555         - check box: I &agree to the above licence terms
556         - Accept button (disabled if check box not checked)
557         - Decline button
558     */
559     setWindowIcon ( QIcon ( QString::fromUtf8 ( ":/png/main/res/fronticon.png" ) ) );
560 
561     QVBoxLayout* pLayout    = new QVBoxLayout ( this );
562     QHBoxLayout* pSubLayout = new QHBoxLayout;
563     QLabel*      lblLicence =
564         new QLabel ( tr ( "This server requires you accept conditions before you can join. Please read these in the chat window." ), this );
565     QCheckBox* chbAgree     = new QCheckBox ( tr ( "I have read the conditions and &agree." ), this );
566     butAccept               = new QPushButton ( tr ( "Accept" ), this );
567     QPushButton* butDecline = new QPushButton ( tr ( "Decline" ), this );
568 
569     pSubLayout->addStretch();
570     pSubLayout->addWidget ( chbAgree );
571     pSubLayout->addWidget ( butAccept );
572     pSubLayout->addWidget ( butDecline );
573     pLayout->addWidget ( lblLicence );
574     pLayout->addLayout ( pSubLayout );
575 
576     // set some properties
577     butAccept->setEnabled ( false );
578     butAccept->setDefault ( true );
579 
580     QObject::connect ( chbAgree, &QCheckBox::stateChanged, this, &CLicenceDlg::OnAgreeStateChanged );
581 
582     QObject::connect ( butAccept, &QPushButton::clicked, this, &CLicenceDlg::accept );
583 
584     QObject::connect ( butDecline, &QPushButton::clicked, this, &CLicenceDlg::reject );
585 }
586 
587 // Help menu -------------------------------------------------------------------
CHelpMenu(const bool bIsClient,QWidget * parent)588 CHelpMenu::CHelpMenu ( const bool bIsClient, QWidget* parent ) : QMenu ( tr ( "&Help" ), parent )
589 {
590     QAction* pAction;
591 
592     // standard help menu consists of about and what's this help
593     if ( bIsClient )
594     {
595         addAction ( tr ( "Getting &Started..." ), this, SLOT ( OnHelpClientGetStarted() ) );
596         addAction ( tr ( "Software &Manual..." ), this, SLOT ( OnHelpSoftwareMan() ) );
597     }
598     else
599     {
600         addAction ( tr ( "Getting &Started..." ), this, SLOT ( OnHelpServerGetStarted() ) );
601     }
602     addSeparator();
603     addAction ( tr ( "What's &This" ), this, SLOT ( OnHelpWhatsThis() ), QKeySequence ( Qt::SHIFT + Qt::Key_F1 ) );
604     addSeparator();
605     pAction = addAction ( tr ( "&About Jamulus..." ), this, SLOT ( OnHelpAbout() ) );
606     pAction->setMenuRole ( QAction::AboutRole ); // required for Mac
607     pAction = addAction ( tr ( "About &Qt..." ), this, SLOT ( OnHelpAboutQt() ) );
608     pAction->setMenuRole ( QAction::AboutQtRole ); // required for Mac
609 }
610 
611 // Language combo box ----------------------------------------------------------
CLanguageComboBox(QWidget * parent)612 CLanguageComboBox::CLanguageComboBox ( QWidget* parent ) : QComboBox ( parent ), iIdxSelectedLanguage ( INVALID_INDEX )
613 {
614     QObject::connect ( this, static_cast<void ( QComboBox::* ) ( int )> ( &QComboBox::activated ), this, &CLanguageComboBox::OnLanguageActivated );
615 }
616 
Init(QString & strSelLanguage)617 void CLanguageComboBox::Init ( QString& strSelLanguage )
618 {
619     // load available translations
620     const QMap<QString, QString>   TranslMap = CLocale::GetAvailableTranslations();
621     QMapIterator<QString, QString> MapIter ( TranslMap );
622 
623     // add translations to the combobox list
624     clear();
625     int iCnt                  = 0;
626     int iIdxOfEnglishLanguage = 0;
627     iIdxSelectedLanguage      = INVALID_INDEX;
628 
629     while ( MapIter.hasNext() )
630     {
631         MapIter.next();
632         addItem ( QLocale ( MapIter.key() ).nativeLanguageName() + " (" + MapIter.key() + ")", MapIter.key() );
633 
634         // store the combo box index of the default english language
635         if ( MapIter.key().compare ( "en" ) == 0 )
636         {
637             iIdxOfEnglishLanguage = iCnt;
638         }
639 
640         // if the selected language is found, store the combo box index
641         if ( MapIter.key().compare ( strSelLanguage ) == 0 )
642         {
643             iIdxSelectedLanguage = iCnt;
644         }
645 
646         iCnt++;
647     }
648 
649     // if the selected language was not found, use the english language
650     if ( iIdxSelectedLanguage == INVALID_INDEX )
651     {
652         strSelLanguage       = "en";
653         iIdxSelectedLanguage = iIdxOfEnglishLanguage;
654     }
655 
656     setCurrentIndex ( iIdxSelectedLanguage );
657 }
658 
OnLanguageActivated(int iLanguageIdx)659 void CLanguageComboBox::OnLanguageActivated ( int iLanguageIdx )
660 {
661     // only update if the language selection is different from the current selected language
662     if ( iIdxSelectedLanguage != iLanguageIdx )
663     {
664         QMessageBox::information ( this, tr ( "Restart Required" ), tr ( "Please restart the application for the language change to take effect." ) );
665 
666         emit LanguageChanged ( itemData ( iLanguageIdx ).toString() );
667     }
668 }
669 #endif
670 
671 /******************************************************************************\
672 * Other Classes                                                                *
673 \******************************************************************************/
674 // Network utility functions ---------------------------------------------------
ParseNetworkAddress(QString strAddress,CHostAddress & HostAddress,bool bEnableIPv6)675 bool NetworkUtil::ParseNetworkAddress ( QString strAddress, CHostAddress& HostAddress, bool bEnableIPv6 )
676 {
677     QHostAddress InetAddr;
678     unsigned int iNetPort = DEFAULT_PORT_NUMBER;
679 
680     // qInfo() << qUtf8Printable ( QString ( "Parsing network address %1" ).arg ( strAddress ) );
681 
682     // init requested host address with invalid address first
683     HostAddress = CHostAddress();
684 
685     // Allow the following address formats:
686     // [addr4or6]
687     // [addr4or6]:port
688     // addr4
689     // addr4:port
690     // hostname
691     // hostname:port
692     // (where addr4or6 is a literal IPv4 or IPv6 address, and addr4 is a literal IPv4 address
693 
694     bool    bLiteralAddr = false;
695     QRegExp rx1 ( "^\\[([^]]*)\\](?::(\\d+))?$" ); // [addr4or6] or [addr4or6]:port
696     QRegExp rx2 ( "^([^:]*)(?::(\\d+))?$" );       // addr4 or addr4:port or host or host:port
697 
698     QString strPort;
699 
700     // parse input address with rx1 and rx2 in turn, capturing address/host and port
701     if ( rx1.indexIn ( strAddress ) == 0 )
702     {
703         // literal address within []
704         strAddress   = rx1.cap ( 1 );
705         strPort      = rx1.cap ( 2 );
706         bLiteralAddr = true; // don't allow hostname within []
707     }
708     else if ( rx2.indexIn ( strAddress ) == 0 )
709     {
710         // hostname or IPv4 address
711         strAddress = rx2.cap ( 1 );
712         strPort    = rx2.cap ( 2 );
713     }
714     else
715     {
716         // invalid format
717         // qInfo() << qUtf8Printable ( QString ( "Invalid address format" ) );
718         return false;
719     }
720 
721     if ( !strPort.isEmpty() )
722     {
723         // a port number was given: extract port number
724         iNetPort = strPort.toInt();
725 
726         if ( iNetPort >= 65536 )
727         {
728             // invalid port number
729             // qInfo() << qUtf8Printable ( QString ( "Invalid port number specified" ) );
730             return false;
731         }
732     }
733 
734     // first try if this is an IP number an can directly applied to QHostAddress
735     if ( InetAddr.setAddress ( strAddress ) )
736     {
737         if ( !bEnableIPv6 && InetAddr.protocol() == QAbstractSocket::IPv6Protocol )
738         {
739             // do not allow IPv6 addresses if not enabled
740             // qInfo() << qUtf8Printable ( QString ( "IPv6 addresses disabled" ) );
741             return false;
742         }
743     }
744     else
745     {
746         // it was no valid IP address. If literal required, return as invalid
747         if ( bLiteralAddr )
748         {
749             // qInfo() << qUtf8Printable ( QString ( "Invalid literal IP address" ) );
750             return false; // invalid address
751         }
752 
753         // try to get host by name, assuming
754         // that the string contains a valid host name string
755         const QHostInfo HostInfo = QHostInfo::fromName ( strAddress );
756 
757         if ( HostInfo.error() != QHostInfo::NoError )
758         {
759             // qInfo() << qUtf8Printable ( QString ( "Invalid hostname" ) );
760             return false; // invalid address
761         }
762 
763         bool bFoundAddr = false;
764 
765         foreach ( const QHostAddress HostAddr, HostInfo.addresses() )
766         {
767             // qInfo() << qUtf8Printable ( QString ( "Resolved network address to %1 for proto %2" ) .arg ( HostAddr.toString() ) .arg (
768             // HostAddr.protocol() ) );
769             if ( HostAddr.protocol() == QAbstractSocket::IPv4Protocol || ( bEnableIPv6 && HostAddr.protocol() == QAbstractSocket::IPv6Protocol ) )
770             {
771                 InetAddr   = HostAddr;
772                 bFoundAddr = true;
773                 break;
774             }
775         }
776 
777         if ( !bFoundAddr )
778         {
779             // no valid address found
780             // qInfo() << qUtf8Printable ( QString ( "No IP address found for hostname" ) );
781             return false;
782         }
783     }
784 
785     // qInfo() << qUtf8Printable ( QString ( "Parsed network address %1" ).arg ( InetAddr.toString() ) );
786 
787     HostAddress = CHostAddress ( InetAddr, iNetPort );
788 
789     return true;
790 }
791 
GetLocalAddress()792 CHostAddress NetworkUtil::GetLocalAddress()
793 {
794     QUdpSocket socket;
795     // As we are using UDP, the connectToHost() does not generate any traffic at all.
796     // We just require a socket which is pointed towards the Internet in
797     // order to find out the IP of our own external interface:
798     socket.connectToHost ( WELL_KNOWN_HOST, WELL_KNOWN_PORT );
799 
800     if ( socket.waitForConnected ( IP_LOOKUP_TIMEOUT ) )
801     {
802         return CHostAddress ( socket.localAddress(), 0 );
803     }
804     else
805     {
806         qWarning() << "could not determine local IPv4 address:" << socket.errorString() << "- using localhost";
807 
808         return CHostAddress ( QHostAddress::LocalHost, 0 );
809     }
810 }
811 
GetLocalAddress6()812 CHostAddress NetworkUtil::GetLocalAddress6()
813 {
814     QUdpSocket socket;
815     // As we are using UDP, the connectToHost() does not generate any traffic at all.
816     // We just require a socket which is pointed towards the Internet in
817     // order to find out the IP of our own external interface:
818     socket.connectToHost ( WELL_KNOWN_HOST6, WELL_KNOWN_PORT );
819 
820     if ( socket.waitForConnected ( IP_LOOKUP_TIMEOUT ) )
821     {
822         return CHostAddress ( socket.localAddress(), 0 );
823     }
824     else
825     {
826         qWarning() << "could not determine local IPv6 address:" << socket.errorString() << "- using localhost";
827 
828         return CHostAddress ( QHostAddress::LocalHostIPv6, 0 );
829     }
830 }
831 
GetCentralServerAddress(const ECSAddType eCentralServerAddressType,const QString & strCentralServerAddress)832 QString NetworkUtil::GetCentralServerAddress ( const ECSAddType eCentralServerAddressType, const QString& strCentralServerAddress )
833 {
834     switch ( eCentralServerAddressType )
835     {
836     case AT_CUSTOM:
837         return strCentralServerAddress;
838     case AT_ANY_GENRE2:
839         return CENTSERV_ANY_GENRE2;
840     case AT_ANY_GENRE3:
841         return CENTSERV_ANY_GENRE3;
842     case AT_GENRE_ROCK:
843         return CENTSERV_GENRE_ROCK;
844     case AT_GENRE_JAZZ:
845         return CENTSERV_GENRE_JAZZ;
846     case AT_GENRE_CLASSICAL_FOLK:
847         return CENTSERV_GENRE_CLASSICAL_FOLK;
848     case AT_GENRE_CHORAL:
849         return CENTSERV_GENRE_CHORAL;
850     default:
851         return DEFAULT_SERVER_ADDRESS; // AT_DEFAULT
852     }
853 }
854 
FixAddress(const QString & strAddress)855 QString NetworkUtil::FixAddress ( const QString& strAddress )
856 {
857     // remove all spaces from the address string
858     return strAddress.simplified().replace ( " ", "" );
859 }
860 
861 // Return whether the given HostAdress is within a private IP range
862 // as per RFC 1918 & RFC 5735.
IsPrivateNetworkIP(const QHostAddress & qhAddr)863 bool NetworkUtil::IsPrivateNetworkIP ( const QHostAddress& qhAddr )
864 {
865     // https://www.rfc-editor.org/rfc/rfc1918
866     // https://www.rfc-editor.org/rfc/rfc5735
867     static QList<QPair<QHostAddress, int>> addresses = {
868         QPair<QHostAddress, int> ( QHostAddress ( "10.0.0.0" ), 8 ),
869         QPair<QHostAddress, int> ( QHostAddress ( "127.0.0.0" ), 8 ),
870         QPair<QHostAddress, int> ( QHostAddress ( "172.16.0.0" ), 12 ),
871         QPair<QHostAddress, int> ( QHostAddress ( "192.168.0.0" ), 16 ),
872     };
873 
874     foreach ( auto item, addresses )
875     {
876         if ( qhAddr.isInSubnet ( item ) )
877         {
878             return true;
879         }
880     }
881     return false;
882 }
883 
884 // CHostAddress methods
885 // Compare() - compare two CHostAddress objects, and return an ordering between them:
886 // 0 - they are equal
887 // <0 - this comes before other
888 // >0 - this comes after other
889 // The order is not important, so long as it is consistent, for use in a binary search.
890 
Compare(const CHostAddress & other) const891 int CHostAddress::Compare ( const CHostAddress& other ) const
892 {
893     // compare port first, as it is cheap, and clients will often use random ports
894 
895     if ( iPort != other.iPort )
896     {
897         return (int) iPort - (int) other.iPort;
898     }
899 
900     // compare protocols before addresses
901 
902     QAbstractSocket::NetworkLayerProtocol thisProto  = InetAddr.protocol();
903     QAbstractSocket::NetworkLayerProtocol otherProto = other.InetAddr.protocol();
904 
905     if ( thisProto != otherProto )
906     {
907         return (int) thisProto - (int) otherProto;
908     }
909 
910     // now we know both addresses are the same protocol
911 
912     if ( thisProto == QAbstractSocket::IPv6Protocol )
913     {
914         // compare IPv6 addresses
915         Q_IPV6ADDR thisAddr  = InetAddr.toIPv6Address();
916         Q_IPV6ADDR otherAddr = other.InetAddr.toIPv6Address();
917 
918         return memcmp ( &thisAddr, &otherAddr, sizeof ( Q_IPV6ADDR ) );
919     }
920 
921     // compare IPv4 addresses
922     quint32 thisAddr  = InetAddr.toIPv4Address();
923     quint32 otherAddr = other.InetAddr.toIPv4Address();
924 
925     return thisAddr < otherAddr ? -1 : thisAddr > otherAddr ? 1 : 0;
926 }
927 
928 // Instrument picture data base ------------------------------------------------
GetTable(const bool bReGenerateTable)929 CVector<CInstPictures::CInstPictProps>& CInstPictures::GetTable ( const bool bReGenerateTable )
930 {
931     // make sure we generate the table only once
932     static bool TableIsInitialized = false;
933 
934     static CVector<CInstPictProps> vecDataBase;
935 
936     if ( !TableIsInitialized || bReGenerateTable )
937     {
938         // instrument picture data base initialization
939         // NOTE: Do not change the order of any instrument in the future!
940         // NOTE: The very first entry is the "not used" element per definition.
941         vecDataBase.Init ( 0 ); // first clear all existing data since we create the list be adding entries
942         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "None" ),
943                                            ":/png/instr/res/instruments/none.png",
944                                            IC_OTHER_INSTRUMENT ) ); // special first element
945         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Drum Set" ),
946                                            ":/png/instr/res/instruments/drumset.png",
947                                            IC_PERCUSSION_INSTRUMENT ) );
948         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Djembe" ),
949                                            ":/png/instr/res/instruments/djembe.png",
950                                            IC_PERCUSSION_INSTRUMENT ) );
951         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Electric Guitar" ),
952                                            ":/png/instr/res/instruments/eguitar.png",
953                                            IC_PLUCKING_INSTRUMENT ) );
954         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Acoustic Guitar" ),
955                                            ":/png/instr/res/instruments/aguitar.png",
956                                            IC_PLUCKING_INSTRUMENT ) );
957         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Bass Guitar" ),
958                                            ":/png/instr/res/instruments/bassguitar.png",
959                                            IC_PLUCKING_INSTRUMENT ) );
960         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Keyboard" ),
961                                            ":/png/instr/res/instruments/keyboard.png",
962                                            IC_KEYBOARD_INSTRUMENT ) );
963         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Synthesizer" ),
964                                            ":/png/instr/res/instruments/synthesizer.png",
965                                            IC_KEYBOARD_INSTRUMENT ) );
966         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Grand Piano" ),
967                                            ":/png/instr/res/instruments/grandpiano.png",
968                                            IC_KEYBOARD_INSTRUMENT ) );
969         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Accordion" ),
970                                            ":/png/instr/res/instruments/accordeon.png",
971                                            IC_KEYBOARD_INSTRUMENT ) );
972         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Vocal" ),
973                                            ":/png/instr/res/instruments/vocal.png",
974                                            IC_OTHER_INSTRUMENT ) );
975         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Microphone" ),
976                                            ":/png/instr/res/instruments/microphone.png",
977                                            IC_OTHER_INSTRUMENT ) );
978         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Harmonica" ),
979                                            ":/png/instr/res/instruments/harmonica.png",
980                                            IC_WIND_INSTRUMENT ) );
981         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Trumpet" ),
982                                            ":/png/instr/res/instruments/trumpet.png",
983                                            IC_WIND_INSTRUMENT ) );
984         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Trombone" ),
985                                            ":/png/instr/res/instruments/trombone.png",
986                                            IC_WIND_INSTRUMENT ) );
987         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "French Horn" ),
988                                            ":/png/instr/res/instruments/frenchhorn.png",
989                                            IC_WIND_INSTRUMENT ) );
990         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Tuba" ),
991                                            ":/png/instr/res/instruments/tuba.png",
992                                            IC_WIND_INSTRUMENT ) );
993         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Saxophone" ),
994                                            ":/png/instr/res/instruments/saxophone.png",
995                                            IC_WIND_INSTRUMENT ) );
996         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Clarinet" ),
997                                            ":/png/instr/res/instruments/clarinet.png",
998                                            IC_WIND_INSTRUMENT ) );
999         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Flute" ),
1000                                            ":/png/instr/res/instruments/flute.png",
1001                                            IC_WIND_INSTRUMENT ) );
1002         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Violin" ),
1003                                            ":/png/instr/res/instruments/violin.png",
1004                                            IC_STRING_INSTRUMENT ) );
1005         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Cello" ),
1006                                            ":/png/instr/res/instruments/cello.png",
1007                                            IC_STRING_INSTRUMENT ) );
1008         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Double Bass" ),
1009                                            ":/png/instr/res/instruments/doublebass.png",
1010                                            IC_STRING_INSTRUMENT ) );
1011         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Recorder" ),
1012                                            ":/png/instr/res/instruments/recorder.png",
1013                                            IC_OTHER_INSTRUMENT ) );
1014         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Streamer" ),
1015                                            ":/png/instr/res/instruments/streamer.png",
1016                                            IC_OTHER_INSTRUMENT ) );
1017         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Listener" ),
1018                                            ":/png/instr/res/instruments/listener.png",
1019                                            IC_OTHER_INSTRUMENT ) );
1020         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Guitar+Vocal" ),
1021                                            ":/png/instr/res/instruments/guitarvocal.png",
1022                                            IC_MULTIPLE_INSTRUMENT ) );
1023         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Keyboard+Vocal" ),
1024                                            ":/png/instr/res/instruments/keyboardvocal.png",
1025                                            IC_MULTIPLE_INSTRUMENT ) );
1026         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Bodhran" ),
1027                                            ":/png/instr/res/instruments/bodhran.png",
1028                                            IC_PERCUSSION_INSTRUMENT ) );
1029         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Bassoon" ),
1030                                            ":/png/instr/res/instruments/bassoon.png",
1031                                            IC_WIND_INSTRUMENT ) );
1032         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Oboe" ),
1033                                            ":/png/instr/res/instruments/oboe.png",
1034                                            IC_WIND_INSTRUMENT ) );
1035         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Harp" ),
1036                                            ":/png/instr/res/instruments/harp.png",
1037                                            IC_STRING_INSTRUMENT ) );
1038         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Viola" ),
1039                                            ":/png/instr/res/instruments/viola.png",
1040                                            IC_STRING_INSTRUMENT ) );
1041         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Congas" ),
1042                                            ":/png/instr/res/instruments/congas.png",
1043                                            IC_PERCUSSION_INSTRUMENT ) );
1044         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Bongo" ),
1045                                            ":/png/instr/res/instruments/bongo.png",
1046                                            IC_PERCUSSION_INSTRUMENT ) );
1047         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Vocal Bass" ),
1048                                            ":/png/instr/res/instruments/vocalbass.png",
1049                                            IC_OTHER_INSTRUMENT ) );
1050         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Vocal Tenor" ),
1051                                            ":/png/instr/res/instruments/vocaltenor.png",
1052                                            IC_OTHER_INSTRUMENT ) );
1053         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Vocal Alto" ),
1054                                            ":/png/instr/res/instruments/vocalalto.png",
1055                                            IC_OTHER_INSTRUMENT ) );
1056         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Vocal Soprano" ),
1057                                            ":/png/instr/res/instruments/vocalsoprano.png",
1058                                            IC_OTHER_INSTRUMENT ) );
1059         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Banjo" ),
1060                                            ":/png/instr/res/instruments/banjo.png",
1061                                            IC_PLUCKING_INSTRUMENT ) );
1062         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Mandolin" ),
1063                                            ":/png/instr/res/instruments/mandolin.png",
1064                                            IC_PLUCKING_INSTRUMENT ) );
1065         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Ukulele" ),
1066                                            ":/png/instr/res/instruments/ukulele.png",
1067                                            IC_PLUCKING_INSTRUMENT ) );
1068         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Bass Ukulele" ),
1069                                            ":/png/instr/res/instruments/bassukulele.png",
1070                                            IC_PLUCKING_INSTRUMENT ) );
1071         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Vocal Baritone" ),
1072                                            ":/png/instr/res/instruments/vocalbaritone.png",
1073                                            IC_OTHER_INSTRUMENT ) );
1074         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Vocal Lead" ),
1075                                            ":/png/instr/res/instruments/vocallead.png",
1076                                            IC_OTHER_INSTRUMENT ) );
1077         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Mountain Dulcimer" ),
1078                                            ":/png/instr/res/instruments/mountaindulcimer.png",
1079                                            IC_STRING_INSTRUMENT ) );
1080         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Scratching" ),
1081                                            ":/png/instr/res/instruments/scratching.png",
1082                                            IC_OTHER_INSTRUMENT ) );
1083         vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CClientSettingsDlg", "Rapping" ),
1084                                            ":/png/instr/res/instruments/rapping.png",
1085                                            IC_OTHER_INSTRUMENT ) );
1086 
1087         // now the table is initialized
1088         TableIsInitialized = true;
1089     }
1090 
1091     return vecDataBase;
1092 }
1093 
IsInstIndexInRange(const int iIdx)1094 bool CInstPictures::IsInstIndexInRange ( const int iIdx )
1095 {
1096     // check if index is in valid range
1097     return ( iIdx >= 0 ) && ( iIdx < GetTable().Size() );
1098 }
1099 
GetResourceReference(const int iInstrument)1100 QString CInstPictures::GetResourceReference ( const int iInstrument )
1101 {
1102     // range check
1103     if ( IsInstIndexInRange ( iInstrument ) )
1104     {
1105         // return the string of the resource reference for accessing the picture
1106         return GetTable()[iInstrument].strResourceReference;
1107     }
1108     else
1109     {
1110         return "";
1111     }
1112 }
1113 
GetName(const int iInstrument)1114 QString CInstPictures::GetName ( const int iInstrument )
1115 {
1116     // range check
1117     if ( IsInstIndexInRange ( iInstrument ) )
1118     {
1119         // return the name of the instrument
1120         return GetTable()[iInstrument].strName;
1121     }
1122     else
1123     {
1124         return "";
1125     }
1126 }
1127 
GetCategory(const int iInstrument)1128 CInstPictures::EInstCategory CInstPictures::GetCategory ( const int iInstrument )
1129 {
1130     // range check
1131     if ( IsInstIndexInRange ( iInstrument ) )
1132     {
1133         // return the name of the instrument
1134         return GetTable()[iInstrument].eInstCategory;
1135     }
1136     else
1137     {
1138         return IC_OTHER_INSTRUMENT;
1139     }
1140 }
1141 
1142 // Locale management class -----------------------------------------------------
GetCountryFlagIconsResourceReference(const QLocale::Country eCountry)1143 QString CLocale::GetCountryFlagIconsResourceReference ( const QLocale::Country eCountry )
1144 {
1145     QString strReturn = "";
1146 
1147     // special flag for none
1148     if ( eCountry == QLocale::AnyCountry )
1149     {
1150         strReturn = ":/png/flags/res/flags/flagnone.png";
1151     }
1152     else
1153     {
1154         // NOTE: The following code was introduced to support old QT versions. The problem
1155         //       is that the number of countries displayed is less than the one displayed
1156         //       with the new code below (which is disabled). Therefore, as soon as the
1157         //       compatibility to the very old versions of QT is not required anymore, use
1158         //       the new code.
1159         // COMPATIBLE FOR OLD QT VERSIONS -> use a table:
1160         QString strISO3166 = "";
1161         switch ( static_cast<int> ( eCountry ) )
1162         {
1163         case 1:
1164             strISO3166 = "af";
1165             break;
1166         case 2:
1167             strISO3166 = "al";
1168             break;
1169         case 3:
1170             strISO3166 = "dz";
1171             break;
1172         case 5:
1173             strISO3166 = "ad";
1174             break;
1175         case 6:
1176             strISO3166 = "ao";
1177             break;
1178         case 10:
1179             strISO3166 = "ar";
1180             break;
1181         case 11:
1182             strISO3166 = "am";
1183             break;
1184         case 12:
1185             strISO3166 = "aw";
1186             break;
1187         case 13:
1188             strISO3166 = "au";
1189             break;
1190         case 14:
1191             strISO3166 = "at";
1192             break;
1193         case 15:
1194             strISO3166 = "az";
1195             break;
1196         case 17:
1197             strISO3166 = "bh";
1198             break;
1199         case 18:
1200             strISO3166 = "bd";
1201             break;
1202         case 20:
1203             strISO3166 = "by";
1204             break;
1205         case 21:
1206             strISO3166 = "be";
1207             break;
1208         case 23:
1209             strISO3166 = "bj";
1210             break;
1211         case 25:
1212             strISO3166 = "bt";
1213             break;
1214         case 26:
1215             strISO3166 = "bo";
1216             break;
1217         case 27:
1218             strISO3166 = "ba";
1219             break;
1220         case 28:
1221             strISO3166 = "bw";
1222             break;
1223         case 30:
1224             strISO3166 = "br";
1225             break;
1226         case 32:
1227             strISO3166 = "bn";
1228             break;
1229         case 33:
1230             strISO3166 = "bg";
1231             break;
1232         case 34:
1233             strISO3166 = "bf";
1234             break;
1235         case 35:
1236             strISO3166 = "bi";
1237             break;
1238         case 36:
1239             strISO3166 = "kh";
1240             break;
1241         case 37:
1242             strISO3166 = "cm";
1243             break;
1244         case 38:
1245             strISO3166 = "ca";
1246             break;
1247         case 39:
1248             strISO3166 = "cv";
1249             break;
1250         case 41:
1251             strISO3166 = "cf";
1252             break;
1253         case 42:
1254             strISO3166 = "td";
1255             break;
1256         case 43:
1257             strISO3166 = "cl";
1258             break;
1259         case 44:
1260             strISO3166 = "cn";
1261             break;
1262         case 47:
1263             strISO3166 = "co";
1264             break;
1265         case 48:
1266             strISO3166 = "km";
1267             break;
1268         case 49:
1269             strISO3166 = "cd";
1270             break;
1271         case 50:
1272             strISO3166 = "cg";
1273             break;
1274         case 52:
1275             strISO3166 = "cr";
1276             break;
1277         case 53:
1278             strISO3166 = "ci";
1279             break;
1280         case 54:
1281             strISO3166 = "hr";
1282             break;
1283         case 55:
1284             strISO3166 = "cu";
1285             break;
1286         case 56:
1287             strISO3166 = "cy";
1288             break;
1289         case 57:
1290             strISO3166 = "cz";
1291             break;
1292         case 58:
1293             strISO3166 = "dk";
1294             break;
1295         case 59:
1296             strISO3166 = "dj";
1297             break;
1298         case 61:
1299             strISO3166 = "do";
1300             break;
1301         case 62:
1302             strISO3166 = "tl";
1303             break;
1304         case 63:
1305             strISO3166 = "ec";
1306             break;
1307         case 64:
1308             strISO3166 = "eg";
1309             break;
1310         case 65:
1311             strISO3166 = "sv";
1312             break;
1313         case 66:
1314             strISO3166 = "gq";
1315             break;
1316         case 67:
1317             strISO3166 = "er";
1318             break;
1319         case 68:
1320             strISO3166 = "ee";
1321             break;
1322         case 69:
1323             strISO3166 = "et";
1324             break;
1325         case 71:
1326             strISO3166 = "fo";
1327             break;
1328         case 73:
1329             strISO3166 = "fi";
1330             break;
1331         case 74:
1332             strISO3166 = "fr";
1333             break;
1334         case 76:
1335             strISO3166 = "gf";
1336             break;
1337         case 77:
1338             strISO3166 = "pf";
1339             break;
1340         case 79:
1341             strISO3166 = "ga";
1342             break;
1343         case 81:
1344             strISO3166 = "ge";
1345             break;
1346         case 82:
1347             strISO3166 = "de";
1348             break;
1349         case 83:
1350             strISO3166 = "gh";
1351             break;
1352         case 85:
1353             strISO3166 = "gr";
1354             break;
1355         case 86:
1356             strISO3166 = "gl";
1357             break;
1358         case 88:
1359             strISO3166 = "gp";
1360             break;
1361         case 90:
1362             strISO3166 = "gt";
1363             break;
1364         case 91:
1365             strISO3166 = "gn";
1366             break;
1367         case 92:
1368             strISO3166 = "gw";
1369             break;
1370         case 93:
1371             strISO3166 = "gy";
1372             break;
1373         case 96:
1374             strISO3166 = "hn";
1375             break;
1376         case 97:
1377             strISO3166 = "hk";
1378             break;
1379         case 98:
1380             strISO3166 = "hu";
1381             break;
1382         case 99:
1383             strISO3166 = "is";
1384             break;
1385         case 100:
1386             strISO3166 = "in";
1387             break;
1388         case 101:
1389             strISO3166 = "id";
1390             break;
1391         case 102:
1392             strISO3166 = "ir";
1393             break;
1394         case 103:
1395             strISO3166 = "iq";
1396             break;
1397         case 104:
1398             strISO3166 = "ie";
1399             break;
1400         case 105:
1401             strISO3166 = "il";
1402             break;
1403         case 106:
1404             strISO3166 = "it";
1405             break;
1406         case 108:
1407             strISO3166 = "jp";
1408             break;
1409         case 109:
1410             strISO3166 = "jo";
1411             break;
1412         case 110:
1413             strISO3166 = "kz";
1414             break;
1415         case 111:
1416             strISO3166 = "ke";
1417             break;
1418         case 113:
1419             strISO3166 = "kp";
1420             break;
1421         case 114:
1422             strISO3166 = "kr";
1423             break;
1424         case 115:
1425             strISO3166 = "kw";
1426             break;
1427         case 116:
1428             strISO3166 = "kg";
1429             break;
1430         case 117:
1431             strISO3166 = "la";
1432             break;
1433         case 118:
1434             strISO3166 = "lv";
1435             break;
1436         case 119:
1437             strISO3166 = "lb";
1438             break;
1439         case 120:
1440             strISO3166 = "ls";
1441             break;
1442         case 122:
1443             strISO3166 = "ly";
1444             break;
1445         case 123:
1446             strISO3166 = "li";
1447             break;
1448         case 124:
1449             strISO3166 = "lt";
1450             break;
1451         case 125:
1452             strISO3166 = "lu";
1453             break;
1454         case 126:
1455             strISO3166 = "mo";
1456             break;
1457         case 127:
1458             strISO3166 = "mk";
1459             break;
1460         case 128:
1461             strISO3166 = "mg";
1462             break;
1463         case 130:
1464             strISO3166 = "my";
1465             break;
1466         case 132:
1467             strISO3166 = "ml";
1468             break;
1469         case 133:
1470             strISO3166 = "mt";
1471             break;
1472         case 135:
1473             strISO3166 = "mq";
1474             break;
1475         case 136:
1476             strISO3166 = "mr";
1477             break;
1478         case 137:
1479             strISO3166 = "mu";
1480             break;
1481         case 138:
1482             strISO3166 = "yt";
1483             break;
1484         case 139:
1485             strISO3166 = "mx";
1486             break;
1487         case 141:
1488             strISO3166 = "md";
1489             break;
1490         case 142:
1491             strISO3166 = "mc";
1492             break;
1493         case 143:
1494             strISO3166 = "mn";
1495             break;
1496         case 145:
1497             strISO3166 = "ma";
1498             break;
1499         case 146:
1500             strISO3166 = "mz";
1501             break;
1502         case 147:
1503             strISO3166 = "mm";
1504             break;
1505         case 148:
1506             strISO3166 = "na";
1507             break;
1508         case 150:
1509             strISO3166 = "np";
1510             break;
1511         case 151:
1512             strISO3166 = "nl";
1513             break;
1514         case 153:
1515             strISO3166 = "nc";
1516             break;
1517         case 154:
1518             strISO3166 = "nz";
1519             break;
1520         case 155:
1521             strISO3166 = "ni";
1522             break;
1523         case 156:
1524             strISO3166 = "ne";
1525             break;
1526         case 157:
1527             strISO3166 = "ng";
1528             break;
1529         case 161:
1530             strISO3166 = "no";
1531             break;
1532         case 162:
1533             strISO3166 = "om";
1534             break;
1535         case 163:
1536             strISO3166 = "pk";
1537             break;
1538         case 165:
1539             strISO3166 = "ps";
1540             break;
1541         case 166:
1542             strISO3166 = "pa";
1543             break;
1544         case 167:
1545             strISO3166 = "pg";
1546             break;
1547         case 168:
1548             strISO3166 = "py";
1549             break;
1550         case 169:
1551             strISO3166 = "pe";
1552             break;
1553         case 170:
1554             strISO3166 = "ph";
1555             break;
1556         case 172:
1557             strISO3166 = "pl";
1558             break;
1559         case 173:
1560             strISO3166 = "pt";
1561             break;
1562         case 174:
1563             strISO3166 = "pr";
1564             break;
1565         case 175:
1566             strISO3166 = "qa";
1567             break;
1568         case 176:
1569             strISO3166 = "re";
1570             break;
1571         case 177:
1572             strISO3166 = "ro";
1573             break;
1574         case 178:
1575             strISO3166 = "ru";
1576             break;
1577         case 179:
1578             strISO3166 = "rw";
1579             break;
1580         case 184:
1581             strISO3166 = "sm";
1582             break;
1583         case 185:
1584             strISO3166 = "st";
1585             break;
1586         case 186:
1587             strISO3166 = "sa";
1588             break;
1589         case 187:
1590             strISO3166 = "sn";
1591             break;
1592         case 188:
1593             strISO3166 = "sc";
1594             break;
1595         case 189:
1596             strISO3166 = "sl";
1597             break;
1598         case 190:
1599             strISO3166 = "sg";
1600             break;
1601         case 191:
1602             strISO3166 = "sk";
1603             break;
1604         case 192:
1605             strISO3166 = "si";
1606             break;
1607         case 194:
1608             strISO3166 = "so";
1609             break;
1610         case 195:
1611             strISO3166 = "za";
1612             break;
1613         case 197:
1614             strISO3166 = "es";
1615             break;
1616         case 198:
1617             strISO3166 = "lk";
1618             break;
1619         case 201:
1620             strISO3166 = "sd";
1621             break;
1622         case 202:
1623             strISO3166 = "sr";
1624             break;
1625         case 204:
1626             strISO3166 = "sz";
1627             break;
1628         case 205:
1629             strISO3166 = "se";
1630             break;
1631         case 206:
1632             strISO3166 = "ch";
1633             break;
1634         case 207:
1635             strISO3166 = "sy";
1636             break;
1637         case 208:
1638             strISO3166 = "tw";
1639             break;
1640         case 209:
1641             strISO3166 = "tj";
1642             break;
1643         case 210:
1644             strISO3166 = "tz";
1645             break;
1646         case 211:
1647             strISO3166 = "th";
1648             break;
1649         case 212:
1650             strISO3166 = "tg";
1651             break;
1652         case 214:
1653             strISO3166 = "to";
1654             break;
1655         case 216:
1656             strISO3166 = "tn";
1657             break;
1658         case 217:
1659             strISO3166 = "tr";
1660             break;
1661         case 221:
1662             strISO3166 = "ug";
1663             break;
1664         case 222:
1665             strISO3166 = "ua";
1666             break;
1667         case 223:
1668             strISO3166 = "ae";
1669             break;
1670         case 224:
1671             strISO3166 = "gb";
1672             break;
1673         case 225:
1674             strISO3166 = "us";
1675             break;
1676         case 227:
1677             strISO3166 = "uy";
1678             break;
1679         case 228:
1680             strISO3166 = "uz";
1681             break;
1682         case 231:
1683             strISO3166 = "ve";
1684             break;
1685         case 232:
1686             strISO3166 = "vn";
1687             break;
1688         case 236:
1689             strISO3166 = "eh";
1690             break;
1691         case 237:
1692             strISO3166 = "ye";
1693             break;
1694         case 239:
1695             strISO3166 = "zm";
1696             break;
1697         case 240:
1698             strISO3166 = "zw";
1699             break;
1700         case 242:
1701             strISO3166 = "me";
1702             break;
1703         case 243:
1704             strISO3166 = "rs";
1705             break;
1706         case 248:
1707             strISO3166 = "ax";
1708             break;
1709         }
1710         strReturn = ":/png/flags/res/flags/" + strISO3166 + ".png";
1711 
1712         // check if file actually exists, if not then invalidate reference
1713         if ( !QFile::exists ( strReturn ) )
1714         {
1715             strReturn = "";
1716         }
1717 
1718         // AT LEAST QT 4.8 IS REQUIRED:
1719         /*
1720                 // There is no direct query of the country code in Qt, therefore we use a
1721                 // workaround: Get the matching locales properties and split the name of
1722                 // that since the second part is the country code
1723                 QList<QLocale> vCurLocaleList = QLocale::matchingLocales ( QLocale::AnyLanguage,
1724                                                                            QLocale::AnyScript,
1725                                                                            eCountry );
1726 
1727                 // check if the matching locales query was successful
1728                 if ( vCurLocaleList.size() > 0 )
1729                 {
1730                     QStringList vstrLocParts = vCurLocaleList.at ( 0 ).name().split("_");
1731 
1732                     // the second split contains the name we need
1733                     if ( vstrLocParts.size() > 1 )
1734                     {
1735                         strReturn = ":/png/flags/res/flags/" + vstrLocParts.at ( 1 ).toLower() + ".png";
1736 
1737                         // check if file actually exists, if not then invalidate reference
1738                         if ( !QFile::exists ( strReturn ) )
1739                         {
1740                             strReturn = "";
1741                         }
1742         //else
1743         //{
1744         //// TEST generate table
1745         //static FILE* pFile = fopen ( "test.dat", "w" );
1746         //fprintf ( pFile, "            case %d: strISO3166 = \"%s\"; break;\n",
1747         //          static_cast<int> ( eCountry ), vstrLocParts.at ( 1 ).toLower().toStdString().c_str() );
1748         //fflush ( pFile );
1749         //}
1750                     }
1751                 }
1752         */
1753     }
1754 
1755     return strReturn;
1756 }
1757 
GetAvailableTranslations()1758 QMap<QString, QString> CLocale::GetAvailableTranslations()
1759 {
1760     QMap<QString, QString> TranslMap;
1761     QDirIterator           DirIter ( ":/translations" );
1762 
1763     // add english language (default which is in the actual source code)
1764     TranslMap["en"] = ""; // empty file name means that the translation load fails and we get the default english language
1765 
1766     while ( DirIter.hasNext() )
1767     {
1768         // get alias of translation file
1769         const QString strCurFileName = DirIter.next();
1770 
1771         // extract only language code (must be at the end, separated with a "_")
1772         const QString strLoc = strCurFileName.right ( strCurFileName.length() - strCurFileName.indexOf ( "_" ) - 1 );
1773 
1774         TranslMap[strLoc] = strCurFileName;
1775     }
1776 
1777     return TranslMap;
1778 }
1779 
FindSysLangTransFileName(const QMap<QString,QString> & TranslMap)1780 QPair<QString, QString> CLocale::FindSysLangTransFileName ( const QMap<QString, QString>& TranslMap )
1781 {
1782     QPair<QString, QString> PairSysLang ( "", "" );
1783     QStringList             slUiLang = QLocale().uiLanguages();
1784 
1785     if ( !slUiLang.isEmpty() )
1786     {
1787         QString strUiLang = QLocale().uiLanguages().at ( 0 );
1788         strUiLang.replace ( "-", "_" );
1789 
1790         // first try to find the complete language string
1791         if ( TranslMap.constFind ( strUiLang ) != TranslMap.constEnd() )
1792         {
1793             PairSysLang.first  = strUiLang;
1794             PairSysLang.second = TranslMap[PairSysLang.first];
1795         }
1796         else
1797         {
1798             // only extract two first characters to identify language (ignoring
1799             // location for getting a simpler implementation -> if the language
1800             // is not correct, the user can change it in the GUI anyway)
1801             if ( strUiLang.length() >= 2 )
1802             {
1803                 PairSysLang.first  = strUiLang.left ( 2 );
1804                 PairSysLang.second = TranslMap[PairSysLang.first];
1805             }
1806         }
1807     }
1808 
1809     return PairSysLang;
1810 }
1811 
LoadTranslation(const QString strLanguage,QCoreApplication * pApp)1812 void CLocale::LoadTranslation ( const QString strLanguage, QCoreApplication* pApp )
1813 {
1814     // The translator objects must be static!
1815     static QTranslator myappTranslator;
1816     static QTranslator myqtTranslator;
1817 
1818     QMap<QString, QString> TranslMap              = CLocale::GetAvailableTranslations();
1819     const QString          strTranslationFileName = TranslMap[strLanguage];
1820 
1821     if ( myappTranslator.load ( strTranslationFileName ) )
1822     {
1823         pApp->installTranslator ( &myappTranslator );
1824     }
1825 
1826     // allows the Qt messages to be translated in the application
1827     if ( myqtTranslator.load ( QLocale ( strLanguage ), "qt", "_", QLibraryInfo::location ( QLibraryInfo::TranslationsPath ) ) )
1828     {
1829         pApp->installTranslator ( &myqtTranslator );
1830     }
1831 }
1832 
1833 /******************************************************************************\
1834 * Global Functions Implementation                                              *
1835 \******************************************************************************/
GetVersionAndNameStr(const bool bWithHtml)1836 QString GetVersionAndNameStr ( const bool bWithHtml )
1837 {
1838     QString strVersionText = "";
1839 
1840     // name, short description and GPL hint
1841     if ( bWithHtml )
1842     {
1843         strVersionText += "<b>";
1844     }
1845     else
1846     {
1847         strVersionText += " *** ";
1848     }
1849 
1850     strVersionText += APP_NAME + QCoreApplication::tr ( ", Version " ) + VERSION;
1851 
1852     if ( bWithHtml )
1853     {
1854         strVersionText += "</b><br>";
1855     }
1856     else
1857     {
1858         strVersionText += "\n *** ";
1859     }
1860 
1861     if ( !bWithHtml )
1862     {
1863         strVersionText += QCoreApplication::tr ( "Internet Jam Session Software" );
1864         strVersionText += "\n *** ";
1865     }
1866 
1867     strVersionText += QCoreApplication::tr ( "Released under the GNU General Public License (GPL)" );
1868 
1869     return strVersionText;
1870 }
1871 
MakeClientNameTitle(QString win,QString client)1872 QString MakeClientNameTitle ( QString win, QString client )
1873 {
1874     QString sReturnString = win;
1875     if ( !client.isEmpty() )
1876     {
1877         sReturnString += " - " + client;
1878     }
1879     return ( sReturnString );
1880 }
1881