Warning, /education/gcompris/src/activities/menu/ConfigurationItem.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - ConfigurationItem.qml
0002  *
0003  * SPDX-FileCopyrightText: 2014-2016 Johnny Jazeix <jazeix@gmail.com>
0004  *
0005  * Authors:
0006  *   Johnny Jazeix <jazeix@gmail.com>
0007  *
0008  *   SPDX-License-Identifier: GPL-3.0-or-later
0009  */
0010 
0011 import QtQuick 2.12
0012 import GCompris 1.0
0013 import QtMultimedia 5.12
0014 
0015 import "../../core"
0016 import "qrc:/gcompris/src/core/core.js" as Core
0017 
0018 Item {
0019     id: dialogConfig
0020 
0021     property var languages: allLangs.languages
0022     property int contentWidth: Math.floor(dialogConfig.width * 0.9)
0023     property var parentActivity
0024     height: contentColumn.height
0025 
0026     LanguageList {
0027         id: allLangs
0028         inMenu: true
0029     }
0030 
0031     Column {
0032         id: contentColumn
0033         spacing: 10 * ApplicationInfo.ratio
0034         width: parent.width
0035 
0036         move: Transition {
0037             NumberAnimation { properties: "x,y"; duration: 120 }
0038         }
0039 
0040         Item {
0041             id: difficultyFilter
0042             width: dialogConfig.contentWidth
0043             height: childrenRect.height
0044             visible: !ApplicationSettings.filterLevelOverridedByCommandLineOption
0045 
0046             GCText {
0047                 id: difficultyLabel
0048                 text: qsTr("Difficulty filter")
0049                 fontSize: mediumSize
0050                 width: dialogConfig.contentWidth
0051                 wrapMode: Text.WordWrap
0052                 anchors.top: parent.top
0053             }
0054 
0055             Row {
0056                 id: starsRow
0057                 width: filterSlider.availableWidth - filterSlider.first.handle.width
0058                 spacing: 0
0059                 anchors.top: difficultyLabel.bottom
0060                 anchors.horizontalCenter: filterSlider.horizontalCenter
0061 
0062                 Repeater {
0063                     id: filterRepeater
0064                     model: 6
0065 
0066                     Image {
0067                         property int starValue: modelData + 1
0068                         source: "qrc:/gcompris/src/core/resource/difficulty" +
0069                         (modelData + 1) + ".svg";
0070                         width: starsRow.width / 6
0071                         height: width * 0.5
0072                         sourceSize.height: height
0073                         sourceSize.width: height
0074                         fillMode: Image.PreserveAspectFit
0075                         opacity: starValue >= minFilter && starValue <= maxFilter ? 1 : 0.4
0076                     }
0077                 }
0078             }
0079 
0080             GCRangeSlider {
0081                 id: filterSlider
0082                 anchors.top: starsRow.bottom
0083                 width: Math.min(300 * ApplicationInfo.ratio, dialogConfig.contentWidth)
0084                 from: 1
0085                 to: 7
0086                 first.value: minFilter
0087                 second.value: maxFilter + 1
0088                 first.onValueChanged: {
0089                     if(first.value >= second.value)
0090                         first.value = second.value - 1;
0091                         else
0092                             minFilter = first.value;
0093                 }
0094                 second.onValueChanged: {
0095                     if(second.value <= first.value)
0096                         second.value = first.value + 1;
0097                         else
0098                             maxFilter = second.value - 1;
0099                 }
0100             }
0101         }
0102 
0103         GCComboBox {
0104             id: languageBox
0105             model: dialogConfig.languages
0106             background: dialogActivityConfig
0107             onCurrentIndexChanged: voicesRow.localeChanged();
0108             label: qsTr("Language selector")
0109         }
0110 
0111         GCDialogCheckBox {
0112             id: enableAutomaticDownloadsBox
0113             width: dialogConfig.contentWidth
0114             checked: isAutomaticDownloadsEnabled
0115             text: qsTr("Enable automatic downloads/updates of external assets")
0116             visible: ApplicationInfo.isDownloadAllowed
0117             onCheckedChanged: {
0118                 isAutomaticDownloadsEnabled = checked;
0119             }
0120         }
0121 
0122         Flow {
0123             id: voicesRow
0124             width: dialogConfig.contentWidth
0125             spacing: 5 * ApplicationInfo.ratio
0126 
0127             property bool haveLocalResource: false
0128 
0129             function localeChanged() {
0130                 var localeText = dialogConfig.languages[languageBox.currentIndex].locale;
0131                 voicesRow.haveLocalResource = DownloadManager.areVoicesRegistered(localeText)
0132             }
0133 
0134             Connections {
0135                 target: DownloadManager
0136 
0137                 onDownloadFinished: voicesRow.localeChanged()
0138                 onResourceRegistered: voicesRow.localeChanged()
0139             }
0140 
0141             GCDialogCheckBox {
0142                 id: voicesText
0143                 width: dialogConfig.contentWidth
0144                 enabled: false
0145                 text: qsTr("Localized voices")
0146                 checked: voicesRow.haveLocalResource
0147             }
0148 
0149             GCButton {
0150                 id: voicesButton
0151                 height: 30 * ApplicationInfo.ratio
0152                 width: dialogConfig.contentWidth
0153                 visible: ApplicationInfo.isDownloadAllowed
0154                 text: voicesRow.haveLocalResource ? qsTr("Check for updates") :
0155                 qsTr("Download")
0156 
0157                 onClicked: {
0158                     if (DownloadManager.downloadResource(
0159                             GCompris.VOICES,
0160                            {"locale": ApplicationInfo.getVoicesLocale(dialogConfig.languages[languageBox.currentIndex].locale)}))
0161                     {
0162                         var downloadDialog = Core.showDownloadDialog(pageView.currentItem, {});
0163                     }
0164                 }
0165             }
0166         }
0167 
0168         GCDialogCheckBox {
0169             id: enableAudioVoicesBox
0170             width: dialogConfig.contentWidth
0171             text: qsTr("Enable audio voices")
0172             checked: isAudioVoicesEnabled
0173             onCheckedChanged: {
0174                 isAudioVoicesEnabled = checked;
0175             }
0176         }
0177 
0178         GCDialogCheckBox {
0179             id: enableAudioEffectsBox
0180             width: dialogConfig.contentWidth
0181             text: qsTr("Enable audio effects")
0182             checked: isAudioEffectsEnabled
0183             onCheckedChanged: {
0184                 isAudioEffectsEnabled = checked;
0185             }
0186         }
0187 
0188         GCText {
0189             id: audioEffectsVolumeText
0190             text: qsTr("Audio effects volume")
0191             width: dialogConfig.contentWidth
0192             fontSize: mediumSize
0193             wrapMode: Text.WordWrap
0194         }
0195 
0196         GCSlider {
0197             id: audioEffectsVolumeSlider
0198             width: 250 * ApplicationInfo.ratio
0199             to: 10
0200             from: 0
0201             value: audioEffectsVolume * 10
0202             onValueChanged: ApplicationSettings.audioEffectsVolume = value / 10;
0203             wheelEnabled: false
0204         }
0205 
0206         GCButton {
0207             id: backgroundMusicButton
0208             height: 30 * ApplicationInfo.ratio
0209             width: dialogConfig.contentWidth
0210             visible: ApplicationInfo.isDownloadAllowed
0211             text: qsTr("Download background music")
0212 
0213             onClicked: {
0214                 if(DownloadManager.downloadResource(GCompris.BACKGROUND_MUSIC))
0215                     var downloadDialog = Core.showDownloadDialog(pageView.currentItem, {});
0216             }
0217         }
0218 
0219         GCDialogCheckBox {
0220             id: enableBackgroundMusicBox
0221             width: dialogConfig.contentWidth
0222             text: qsTr("Enable background music")
0223             checked: isBackgroundMusicEnabled
0224             onCheckedChanged: {
0225                 isBackgroundMusicEnabled = checked;
0226             }
0227         }
0228 
0229         GCText {
0230             id: musicText
0231             text: qsTr("Background Music")
0232             width: dialogConfig.contentWidth
0233             fontSize: mediumSize
0234             wrapMode: Text.WordWrap
0235         }
0236 
0237         Row {
0238             height: 30 * ApplicationInfo.ratio
0239             width: background.width * 0.8
0240             spacing: 5 * ApplicationInfo.ratio
0241             GCButton {
0242                 id: backgroundMusicName
0243                 height: parent.height
0244                 width: parent.width - 35 * ApplicationInfo.ratio
0245                 text: {
0246                     if(backgroundMusic.playbackState !== Audio.PlayingState || backgroundMusic.muted)
0247                         return qsTr("Not playing")
0248                     else if (backgroundMusic.metaDataMusic[0] !== undefined)
0249                         return (qsTr("Title: %1  Artist: %2").arg(backgroundMusic.metaDataMusic[0]).arg(backgroundMusic.metaDataMusic[1]))
0250                     else if (String(backgroundMusic.source).slice(0, 37) === "qrc:/gcompris/src/core/resource/intro")
0251                         return qsTr("Introduction music")
0252                     return ""
0253                 }
0254                 onClicked: {
0255                     dialogConfig.visible = false
0256                     backgroundMusicList.visible = true
0257                 }
0258             }
0259             Image {
0260                 source: "qrc:/gcompris/src/core/resource/bar_next.svg"
0261                 height: 30 * ApplicationInfo.ratio
0262                 sourceSize.width: height
0263                 visible: (backgroundMusic.playbackState === Audio.PlayingState && !backgroundMusic.muted)
0264                 MouseArea {
0265                     anchors.fill: parent
0266                     enabled: parent.visible
0267                     onClicked: backgroundMusic.nextAudio()
0268                 }
0269             }
0270         }
0271 
0272         GCText {
0273             id: backgroundMusicVolumeText
0274             text: qsTr("Background music volume")
0275             fontSize: mediumSize
0276             width: dialogConfig.contentWidth
0277             wrapMode: Text.WordWrap
0278         }
0279 
0280         GCSlider {
0281             id: backgroundMusicVolumeSlider
0282             width: 250 * ApplicationInfo.ratio
0283             to: 10
0284             from: 0
0285             value: backgroundMusicVolume * 10
0286             onValueChanged: ApplicationSettings.backgroundMusicVolume = value / 10;
0287             wheelEnabled: false
0288         }
0289 
0290         Connections {
0291             target: DownloadManager
0292             onDownloadFinished: wordsetBox.updateStatus()
0293             onBackgroundMusicRegistered: {
0294                 allBackgroundMusic = ApplicationInfo.getBackgroundMusicFromRcc()
0295                 if(filteredBackgroundMusic.length === 0) {
0296                     filteredBackgroundMusic = allBackgroundMusic
0297                 }
0298             }
0299         }
0300 
0301         GCDialogCheckBox {
0302             id: wordsetBox
0303             width: dialogConfig.contentWidth
0304             checked: DownloadManager.isDataRegistered("words-webp")
0305             text: checked ? qsTr("Full word image set is installed") : qsTr("Full word image set is not installed")
0306             visible: ApplicationInfo.isDownloadAllowed
0307             enabled: false
0308 
0309             function updateStatus() {
0310                 checked = DownloadManager.isDataRegistered("words-webp")
0311             }
0312         }
0313 
0314         GCButton {
0315             id: wordsetButton
0316             height: 30 * ApplicationInfo.ratio
0317             width: dialogConfig.contentWidth
0318             visible: ApplicationInfo.isDownloadAllowed
0319             text: qsTr("Download full word image set")
0320 
0321             onClicked: {
0322                 if(DownloadManager.downloadResource(GCompris.WORDSET))
0323                     var downloadDialog = Core.showDownloadDialog(pageView.currentItem, {});
0324             }
0325         }
0326 
0327         GCDialogCheckBox {
0328             id: enableFullscreenBox
0329             width: dialogConfig.contentWidth
0330             text: qsTr("Fullscreen")
0331             checked: isFullscreen
0332             onCheckedChanged: {
0333                 isFullscreen = checked;
0334             }
0335             visible: !ApplicationInfo.isMobile
0336         }
0337 
0338         GCDialogCheckBox {
0339             id: enableVirtualKeyboardBox
0340             width: dialogConfig.contentWidth
0341             text: qsTr("Virtual Keyboard")
0342             checked: isVirtualKeyboard
0343             onCheckedChanged: {
0344                 isVirtualKeyboard = checked;
0345             }
0346         }
0347 
0348         GCDialogCheckBox {
0349             id: sectionVisibleBox
0350             width: dialogConfig.contentWidth
0351             checked: sectionVisible
0352             text: qsTr("The activity section menu is visible")
0353             onCheckedChanged: {
0354                 sectionVisible = checked;
0355             }
0356         }
0357 
0358         GCDialogCheckBox {
0359             id: exitConfirmationBox
0360             width: dialogConfig.contentWidth
0361             checked: exitConfirmation
0362             text: qsTr("Ask for confirmation to exit")
0363             visible: ApplicationInfo.isMobile ? false : true
0364             onCheckedChanged: {
0365                 exitConfirmation = checked;
0366             }
0367         }
0368 
0369         GCComboBox {
0370             id: fontBox
0371             model: fonts
0372             background: dialogActivityConfig
0373             label: qsTr("Font selector")
0374         }
0375 
0376         GCText {
0377             id: baseFontSizeText
0378             text: qsTr("Font size")
0379             width: dialogConfig.contentWidth
0380             fontSize: mediumSize
0381             wrapMode: Text.WordWrap
0382         }
0383 
0384         Flow {
0385             spacing: 5
0386             width: dialogConfig.contentWidth
0387             GCSlider {
0388                 id: baseFontSizeSlider
0389                 width: 250 * ApplicationInfo.ratio
0390                 to: ApplicationSettings.baseFontSizeMax
0391                 from: ApplicationSettings.baseFontSizeMin
0392                 value: baseFontSize
0393                 onValueChanged: ApplicationSettings.baseFontSize = value;
0394                 wheelEnabled: false
0395             }
0396             GCButton {
0397                 height: 30 * ApplicationInfo.ratio
0398                 text: qsTr("Default");
0399                 onClicked: baseFontSizeSlider.value = 0.0
0400             }
0401         }
0402 
0403         GCComboBox {
0404             id: fontCapitalizationBox
0405             model: fontCapitalizationModel
0406             background: dialogActivityConfig
0407             label: qsTr("Font Capitalization")
0408         }
0409 
0410         GCText {
0411             id: fontLetterSpacingText
0412             text: qsTr("Font letter spacing")
0413             fontSize: mediumSize
0414             width: dialogConfig.contentWidth
0415             wrapMode: Text.WordWrap
0416         }
0417 
0418         Flow {
0419             spacing: 5
0420             width: dialogConfig.contentWidth
0421             GCSlider {
0422                 id: fontLetterSpacingSlider
0423                 width: 250 * ApplicationInfo.ratio
0424                 to: ApplicationSettings.fontLetterSpacingMax
0425                 from: ApplicationSettings.fontLetterSpacingMin
0426                 value: fontLetterSpacing
0427                 onValueChanged: ApplicationSettings.fontLetterSpacing = value;
0428                 wheelEnabled: false
0429             }
0430             GCButton {
0431                 height: 30 * ApplicationInfo.ratio
0432                 text: qsTr("Default");
0433                 onClicked: fontLetterSpacingSlider.value = ApplicationSettings.fontLetterSpacingMin
0434             }
0435         }
0436     }
0437 
0438     property bool isAudioVoicesEnabled: ApplicationSettings.isAudioVoicesEnabled
0439     property bool isAudioEffectsEnabled: ApplicationSettings.isAudioEffectsEnabled
0440     property bool isBackgroundMusicEnabled: ApplicationSettings.isBackgroundMusicEnabled
0441     property bool isFullscreen: ApplicationSettings.isFullscreen
0442     property bool isVirtualKeyboard: ApplicationSettings.isVirtualKeyboard
0443     property bool isAutomaticDownloadsEnabled: ApplicationSettings.isAutomaticDownloadsEnabled
0444     property bool sectionVisible: ApplicationSettings.sectionVisible
0445     property bool exitConfirmation: ApplicationSettings.exitConfirmation
0446     property var filteredBackgroundMusic: ApplicationSettings.filteredBackgroundMusic
0447     property var allBackgroundMusic: ApplicationInfo.getBackgroundMusicFromRcc()
0448     property int baseFontSize  // don't bind to ApplicationSettings.baseFontSize
0449     property real fontLetterSpacing // don't bind to ApplicationSettings.fontLetterSpacing
0450     // or we get a binding loop warning
0451     property real backgroundMusicVolume
0452     property real audioEffectsVolume
0453     property int minFilter
0454     property int maxFilter
0455 
0456     function extractMusicNameFromPath(musicPath) {
0457         var musicDirectoryPath = ApplicationInfo.getAudioFilePath("backgroundMusic/")
0458         var musicName = String(musicPath)
0459         musicName = musicName.slice(musicDirectoryPath.length, musicName.length)
0460         return musicName.slice(0, musicName.lastIndexOf('.'))
0461     }
0462 
0463     function loadFromConfig() {
0464         // Synchronize settings with data
0465         isAudioVoicesEnabled = ApplicationSettings.isAudioVoicesEnabled
0466         enableAudioVoicesBox.checked = isAudioVoicesEnabled
0467 
0468         isAudioEffectsEnabled = ApplicationSettings.isAudioEffectsEnabled
0469         enableAudioEffectsBox.checked = isAudioEffectsEnabled
0470 
0471         isBackgroundMusicEnabled = ApplicationSettings.isBackgroundMusicEnabled
0472         enableBackgroundMusicBox.checked = isBackgroundMusicEnabled
0473 
0474         isFullscreen = ApplicationSettings.isFullscreen
0475         enableFullscreenBox.checked = isFullscreen
0476 
0477         isVirtualKeyboard = ApplicationSettings.isVirtualKeyboard
0478         enableVirtualKeyboardBox.checked = isVirtualKeyboard
0479 
0480         isAutomaticDownloadsEnabled = ApplicationSettings.isAutomaticDownloadsEnabled
0481         enableAutomaticDownloadsBox.checked = isAutomaticDownloadsEnabled
0482 
0483         minFilter = ApplicationSettings.filterLevelMin
0484         maxFilter = ApplicationSettings.filterLevelMax
0485 
0486         sectionVisible = ApplicationSettings.sectionVisible
0487         sectionVisibleBox.checked = sectionVisible
0488 
0489         exitConfirmation = ApplicationSettings.exitConfirmation
0490         exitConfirmationBox.checked = exitConfirmation
0491 
0492         baseFontSize = ApplicationSettings.baseFontSize
0493         fontLetterSpacing = ApplicationSettings.fontLetterSpacing
0494         backgroundMusicVolume = ApplicationSettings.backgroundMusicVolume
0495         audioEffectsVolume = ApplicationSettings.audioEffectsVolume
0496         filteredBackgroundMusic = ApplicationSettings.filteredBackgroundMusic.slice()
0497         allBackgroundMusic = ApplicationInfo.getBackgroundMusicFromRcc()
0498         if(filteredBackgroundMusic.length === 0)
0499             filteredBackgroundMusic = allBackgroundMusic
0500         // Set locale
0501         for(var i = 0 ; i < dialogConfig.languages.length ; i ++) {
0502             if(dialogConfig.languages[i].locale === ApplicationSettings.locale) {
0503                 languageBox.currentIndex = i;
0504                 break;
0505             }
0506         }
0507 
0508         // Set font
0509         for(i = 0 ; i < fonts.count ; i ++) {
0510             if(fonts.get(i).text === ApplicationSettings.font) {
0511                 fontBox.currentIndex = i;
0512                 break;
0513             }
0514         }
0515 
0516         // Set font capitalization
0517         for(i = 0 ; i < fontCapitalizationModel.length ; i ++) {
0518             if(fontCapitalizationModel[i].value === ApplicationSettings.fontCapitalization) {
0519                 fontCapitalizationBox.currentIndex = i;
0520                 break;
0521             }
0522         }
0523     }
0524 
0525     function save() {
0526         ApplicationSettings.isAudioVoicesEnabled = isAudioVoicesEnabled
0527         ApplicationSettings.isAudioEffectsEnabled = isAudioEffectsEnabled
0528         ApplicationSettings.isBackgroundMusicEnabled = isBackgroundMusicEnabled
0529 
0530         if(filteredBackgroundMusic.length === 0) {
0531             filteredBackgroundMusic = ApplicationInfo.getBackgroundMusicFromRcc()
0532         }
0533         ApplicationSettings.filteredBackgroundMusic = filteredBackgroundMusic.slice()
0534 
0535         ApplicationSettings.isFullscreen = isFullscreen
0536         ApplicationSettings.isVirtualKeyboard = isVirtualKeyboard
0537         ApplicationSettings.isAutomaticDownloadsEnabled = isAutomaticDownloadsEnabled
0538         ApplicationSettings.sectionVisible = sectionVisible
0539         ApplicationSettings.exitConfirmation = exitConfirmation
0540         ApplicationSettings.isEmbeddedFont = fonts.get(fontBox.currentIndex).isLocalResource;
0541         ApplicationSettings.font = fonts.get(fontBox.currentIndex).text
0542         ApplicationSettings.fontCapitalization = fontCapitalizationModel[fontCapitalizationBox.currentIndex].value
0543 
0544         if(ApplicationSettings.filterLevelMin !== minFilter ||
0545            ApplicationSettings.filterLevelMax !== maxFilter) {
0546                ApplicationSettings.filterLevelMin = minFilter
0547                ApplicationSettings.filterLevelMax = maxFilter
0548                ActivityInfoTree.minMaxFiltersChanged(minFilter, maxFilter)
0549         }
0550 
0551         ApplicationSettings.saveBaseFontSize();
0552         ApplicationSettings.notifyFontLetterSpacingChanged();
0553 
0554         if (ApplicationSettings.locale !== dialogConfig.languages[languageBox.currentIndex].locale) {
0555             ApplicationSettings.locale = dialogConfig.languages[languageBox.currentIndex].locale
0556             if(ApplicationInfo.isDownloadAllowed && !DownloadManager.isDataRegistered(
0557                         "voices-" + ApplicationInfo.CompressedAudio + "/" +
0558                         ApplicationInfo.getVoicesLocale(ApplicationSettings.locale)
0559                         ))
0560             {
0561                 // ask for downloading new voices
0562                 parentActivity.newVoicesSignal();
0563             } else {
0564                 // check for updates or/and register new voices
0565                 DownloadManager.updateResource(GCompris.VOICES, {"locale": ApplicationInfo.getVoicesLocale(ApplicationSettings.locale)});
0566             }
0567         }
0568     }
0569 
0570     ListModel {
0571         id: fonts
0572         Component.onCompleted: {
0573             var systemFonts = Qt.fontFamilies();
0574             var rccFonts = ApplicationInfo.getFontsFromRcc();
0575 
0576             // Remove explicitly all *symbol* and *ding* fonts
0577             var excludedFonts = ApplicationInfo.getSystemExcludedFonts();
0578             excludedFonts.push("ding");
0579             excludedFonts.push("symbol");
0580 
0581             // first display fonts from rcc
0582             for(var i = 0 ; i < rccFonts.length ; ++ i) {
0583                 // Append fonts from resources
0584                 fonts.append({ "text": rccFonts[i], "isLocalResource": true });
0585             }
0586 
0587             for(i = 0 ; i < systemFonts.length ; ++ i) {
0588                 var isExcluded = false;
0589                 var systemFont = systemFonts[i].toLowerCase();
0590                 // Remove symbol fonts
0591                 for(var j = 0 ; j < excludedFonts.length ; ++ j) {
0592                     if(systemFont.indexOf(excludedFonts[j].toLowerCase()) !== -1) {
0593                         isExcluded = true;
0594                         break;
0595                     }
0596                 }
0597 
0598                 // Remove fonts from rcc (if you have a default font from rcc, Qt will add it to systemFonts)
0599                 for(j = 0 ; j < rccFonts.length ; ++ j) {
0600                     if(rccFonts[j].toLowerCase().indexOf(systemFont) !== -1) {
0601                         isExcluded = true;
0602                         break;
0603                     }
0604                 }
0605 
0606                 // Finally, we know if we add this font or not
0607                 if(!isExcluded) {
0608                     fonts.append({ "text": systemFonts[i], "isLocalResource": false });
0609                 }
0610             }
0611         }
0612     }
0613 
0614     property var fontCapitalizationModel: [
0615         { text: qsTr("Mixed case (default)"), value: Font.MixedCase },
0616         { text: qsTr("All uppercase"), value: Font.AllUppercase },
0617         { text: qsTr("All lowercase"), value: Font.AllLowercase }
0618     ]
0619 
0620     function isFilteredBackgroundMusicChanged() {
0621         initialFilteredMusic = ApplicationSettings.filteredBackgroundMusic
0622         if(initialFilteredMusic.length !== filteredBackgroundMusic.length)
0623             return true
0624         for(var i = 0; i < initialFilteredMusic.length; i++)
0625             if(filteredBackgroundMusic.indexOf(initialFilteredMusic[i]) === -1)
0626                 return true
0627 
0628         return false
0629     }
0630 
0631     function hasConfigChanged() {
0632         return (ApplicationSettings.locale !== dialogConfig.languages[languageBox.currentIndex].locale ||
0633         (ApplicationSettings.sectionVisible != sectionVisible) ||
0634         (ApplicationSettings.exitConfirmation != exitConfirmation) ||
0635         (ApplicationSettings.font = fonts.get(fontBox.currentIndex).text) ||
0636         (ApplicationSettings.isEmbeddedFont !== fonts.get(fontBox.currentIndex).isLocalResource) ||
0637         (ApplicationSettings.isEmbeddedFont !== fonts.get(fontBox.currentIndex).isLocalResource) ||
0638         (ApplicationSettings.fontCapitalization !== fontCapitalizationModel[(fontcapitalizationBox.currentIndex)].value) ||
0639         (ApplicationSettings.fontLetterSpacing != fontLetterSpacing) ||
0640         (ApplicationSettings.isAudioVoicesEnabled != isAudioVoicesEnabled) ||
0641         (ApplicationSettings.isAudioEffectsEnabled != isAudioEffectsEnabled) ||
0642         (ApplicationSettings.isBackgroundMusicEnabled != isBackgroundMusicEnabled) ||
0643         (ApplicationSettings.isFullscreen != isFullscreen) ||
0644         (ApplicationSettings.isVirtualKeyboard != isVirtualKeyboard) ||
0645         (ApplicationSettings.isAutomaticDownloadsEnabled != isAutomaticDownloadsEnabled) ||
0646         (ApplicationSettings.baseFontSize != baseFontSize) ||
0647         isFilteredBackgroundMusicChanged()
0648         );
0649     }
0650 }