Merge pull request #26126 from stephan49/fix-pipewire-unlock-error
[xbmc.git] / xbmc / video / dialogs / GUIDialogSubtitleSettings.cpp
blobab476a43d9c9ccaddd192a721c190b56481a04d6
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIDialogSubtitleSettings.h"
11 #include "FileItem.h"
12 #include "GUIDialogSubtitles.h"
13 #include "GUIPassword.h"
14 #include "ServiceBroker.h"
15 #include "URL.h"
16 #include "addons/Skin.h"
17 #include "addons/VFSEntry.h"
18 #include "application/Application.h"
19 #include "application/ApplicationComponents.h"
20 #include "application/ApplicationPlayer.h"
21 #include "cores/IPlayer.h"
22 #include "dialogs/GUIDialogFileBrowser.h"
23 #include "dialogs/GUIDialogYesNo.h"
24 #include "guilib/GUIComponent.h"
25 #include "guilib/GUIWindowManager.h"
26 #include "guilib/LocalizeStrings.h"
27 #include "profiles/ProfileManager.h"
28 #include "settings/AdvancedSettings.h"
29 #include "settings/MediaSettings.h"
30 #include "settings/MediaSourceSettings.h"
31 #include "settings/Settings.h"
32 #include "settings/SettingsComponent.h"
33 #include "settings/lib/Setting.h"
34 #include "settings/lib/SettingDefinitions.h"
35 #include "settings/lib/SettingsManager.h"
36 #include "utils/FileUtils.h"
37 #include "utils/LangCodeExpander.h"
38 #include "utils/StringUtils.h"
39 #include "utils/URIUtils.h"
40 #include "utils/Variant.h"
41 #include "utils/log.h"
42 #include "video/VideoDatabase.h"
44 #include <string>
45 #include <vector>
47 #define SETTING_SUBTITLE_ENABLE "subtitles.enable"
48 #define SETTING_SUBTITLE_DELAY "subtitles.delay"
49 #define SETTING_SUBTITLE_STREAM "subtitles.stream"
50 #define SETTING_SUBTITLE_BROWSER "subtitles.browser"
51 #define SETTING_SUBTITLE_SEARCH "subtitles.search"
52 #define SETTING_MAKE_DEFAULT "audio.makedefault"
54 CGUIDialogSubtitleSettings::CGUIDialogSubtitleSettings()
55 : CGUIDialogSettingsManualBase(WINDOW_DIALOG_SUBTITLE_OSD_SETTINGS, "DialogSettings.xml")
56 { }
58 CGUIDialogSubtitleSettings::~CGUIDialogSubtitleSettings() = default;
60 void CGUIDialogSubtitleSettings::FrameMove()
62 const auto& components = CServiceBroker::GetAppComponents();
63 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
64 if (appPlayer->HasPlayer())
66 const CVideoSettings videoSettings = appPlayer->GetVideoSettings();
68 // these settings can change on the fly
69 //! @todo m_settingsManager->SetBool(SETTING_SUBTITLE_ENABLE, g_application.GetAppPlayer().GetSubtitleVisible());
70 // \-> Unless subtitle visibility can change on the fly, while Dialog is up, this code should be removed.
71 GetSettingsManager()->SetNumber(SETTING_SUBTITLE_DELAY,
72 static_cast<double>(videoSettings.m_SubtitleDelay));
73 //! @todo (needs special handling): m_settingsManager->SetInt(SETTING_SUBTITLE_STREAM, g_application.GetAppPlayer().GetSubtitle());
76 CGUIDialogSettingsManualBase::FrameMove();
79 bool CGUIDialogSubtitleSettings::OnMessage(CGUIMessage& message)
81 if (message.GetMessage() == GUI_MSG_SUBTITLE_DOWNLOADED)
83 Close();
85 return CGUIDialogSettingsManualBase::OnMessage(message);
88 void CGUIDialogSubtitleSettings::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
90 if (setting == NULL)
91 return;
93 auto& components = CServiceBroker::GetAppComponents();
94 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
96 CGUIDialogSettingsManualBase::OnSettingChanged(setting);
98 const std::string &settingId = setting->GetId();
99 if (settingId == SETTING_SUBTITLE_ENABLE)
101 bool value = std::static_pointer_cast<const CSettingBool>(setting)->GetValue();
102 if (value)
104 // Ensure that we use/store the subtitle stream the user currently sees in the dialog.
105 appPlayer->SetSubtitle(m_subtitleStream);
107 appPlayer->SetSubtitleVisible(value);
109 else if (settingId == SETTING_SUBTITLE_DELAY)
111 float value = static_cast<float>(std::static_pointer_cast<const CSettingNumber>(setting)->GetValue());
112 appPlayer->SetSubTitleDelay(value);
114 else if (settingId == SETTING_SUBTITLE_STREAM)
116 m_subtitleStream = std::static_pointer_cast<const CSettingInt>(setting)->GetValue();
117 appPlayer->SetSubtitle(m_subtitleStream);
121 std::string CGUIDialogSubtitleSettings::BrowseForSubtitle()
123 std::string extras;
124 for (const auto& vfsAddon : CServiceBroker::GetVFSAddonCache().GetAddonInstances())
126 if (vfsAddon->ID() == "vfs.rar" || vfsAddon->ID() == "vfs.libarchive")
127 extras += '|' + vfsAddon->GetExtensions();
130 std::string strPath;
131 const std::string dynPath{g_application.CurrentFileItem().GetDynPath()};
132 if (URIUtils::IsInRAR(dynPath) || URIUtils::IsInZIP(dynPath))
134 strPath = CURL(dynPath).GetHostName();
136 else if (!URIUtils::IsPlugin(dynPath))
138 strPath = dynPath;
141 std::string strMask =
142 ".utf|.utf8|.utf-8|.sub|.srt|.smi|.rt|.txt|.ssa|.aqt|.jss|.ass|.vtt|.idx|.zip|.sup";
144 if (g_application.GetCurrentPlayer() == "VideoPlayer")
145 strMask = ".srt|.zip|.ifo|.smi|.sub|.idx|.ass|.ssa|.vtt|.txt|.sup";
147 strMask += extras;
149 std::vector<CMediaSource> shares(*CMediaSourceSettings::GetInstance().GetSources("video"));
150 if (CMediaSettings::GetInstance().GetAdditionalSubtitleDirectoryChecked() != -1 && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SUBTITLES_CUSTOMPATH).empty())
152 CMediaSource share;
153 std::vector<std::string> paths;
154 if (!strPath.empty())
156 paths.push_back(URIUtils::GetDirectory(strPath));
158 paths.push_back(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SUBTITLES_CUSTOMPATH));
159 share.FromNameAndPaths("video",g_localizeStrings.Get(21367),paths);
160 shares.push_back(share);
161 strPath = share.strPath;
162 URIUtils::AddSlashAtEnd(strPath);
165 if (CGUIDialogFileBrowser::ShowAndGetFile(shares, strMask, g_localizeStrings.Get(293), strPath, false, true)) // "subtitles"
167 if (URIUtils::HasExtension(strPath, ".sub"))
169 if (CFileUtils::Exists(URIUtils::ReplaceExtension(strPath, ".idx")))
170 strPath = URIUtils::ReplaceExtension(strPath, ".idx");
173 return strPath;
176 return "";
179 void CGUIDialogSubtitleSettings::OnSettingAction(const std::shared_ptr<const CSetting>& setting)
181 if (setting == NULL)
182 return;
184 CGUIDialogSettingsManualBase::OnSettingAction(setting);
186 const std::string &settingId = setting->GetId();
187 if (settingId == SETTING_SUBTITLE_BROWSER)
189 std::string strPath = BrowseForSubtitle();
190 if (!strPath.empty())
192 auto& components = CServiceBroker::GetAppComponents();
193 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
194 appPlayer->AddSubtitle(strPath);
195 Close();
198 else if (settingId == SETTING_SUBTITLE_SEARCH)
200 auto dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSubtitles>(WINDOW_DIALOG_SUBTITLES);
201 if (dialog)
203 dialog->Open();
204 m_subtitleStreamSetting->UpdateDynamicOptions();
207 else if (settingId == SETTING_MAKE_DEFAULT)
208 Save();
211 bool CGUIDialogSubtitleSettings::Save()
213 const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();
215 if (!g_passwordManager.CheckSettingLevelLock(SettingLevel::Expert) &&
216 profileManager->GetMasterProfile().getLockMode() != LockMode::EVERYONE)
217 return true;
219 // prompt user if they are sure
220 if (!CGUIDialogYesNo::ShowAndGetInput(CVariant{12376}, CVariant{12377}))
221 return true;
223 // reset the settings
224 CVideoDatabase db;
225 if (!db.Open())
226 return true;
228 db.EraseAllVideoSettings();
229 db.Close();
230 const auto& components = CServiceBroker::GetAppComponents();
231 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
233 CMediaSettings::GetInstance().GetDefaultVideoSettings() = appPlayer->GetVideoSettings();
234 CMediaSettings::GetInstance().GetDefaultVideoSettings().m_SubtitleStream = -1;
235 CServiceBroker::GetSettingsComponent()->GetSettings()->Save();
237 return true;
240 void CGUIDialogSubtitleSettings::SetupView()
242 CGUIDialogSettingsManualBase::SetupView();
244 SetHeading(24133);
245 SET_CONTROL_HIDDEN(CONTROL_SETTINGS_OKAY_BUTTON);
246 SET_CONTROL_HIDDEN(CONTROL_SETTINGS_CUSTOM_BUTTON);
247 SET_CONTROL_LABEL(CONTROL_SETTINGS_CANCEL_BUTTON, 15067);
250 void CGUIDialogSubtitleSettings::InitializeSettings()
252 CGUIDialogSettingsManualBase::InitializeSettings();
254 const auto& components = CServiceBroker::GetAppComponents();
255 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
257 const std::shared_ptr<CSettingCategory> category = AddCategory("audiosubtitlesettings", -1);
258 if (category == NULL)
260 CLog::Log(LOGERROR, "CGUIDialogSubtitleSettings: unable to setup settings");
261 return;
264 // get all necessary setting groups
265 const std::shared_ptr<CSettingGroup> groupAudio = AddGroup(category);
266 if (groupAudio == NULL)
268 CLog::Log(LOGERROR, "CGUIDialogSubtitleSettings: unable to setup settings");
269 return;
271 const std::shared_ptr<CSettingGroup> groupSubtitles = AddGroup(category);
272 if (groupSubtitles == NULL)
274 CLog::Log(LOGERROR, "CGUIDialogSubtitleSettings: unable to setup settings");
275 return;
277 const std::shared_ptr<CSettingGroup> groupSaveAsDefault = AddGroup(category);
278 if (groupSaveAsDefault == NULL)
280 CLog::Log(LOGERROR, "CGUIDialogSubtitleSettings: unable to setup settings");
281 return;
284 bool usePopup = g_SkinInfo->HasSkinFile("DialogSlider.xml");
286 const CVideoSettings videoSettings = appPlayer->GetVideoSettings();
288 if (appPlayer->HasPlayer())
290 appPlayer->GetSubtitleCapabilities(m_subtitleCapabilities);
293 // subtitle settings
294 m_subtitleVisible = appPlayer->GetSubtitleVisible();
296 // subtitle enabled setting
297 AddToggle(groupSubtitles, SETTING_SUBTITLE_ENABLE, 13397, SettingLevel::Basic, m_subtitleVisible);
299 // subtitle delay setting
300 if (SupportsSubtitleFeature(IPlayerSubtitleCaps::OFFSET))
302 std::shared_ptr<CSettingNumber> settingSubtitleDelay = AddSlider(
303 groupSubtitles, SETTING_SUBTITLE_DELAY, 22006, SettingLevel::Basic,
304 videoSettings.m_SubtitleDelay, 0,
305 -CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoSubsDelayRange,
306 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoSubsDelayStep,
307 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoSubsDelayRange, 22006,
308 usePopup);
309 std::static_pointer_cast<CSettingControlSlider>(settingSubtitleDelay->GetControl())->SetFormatter(SettingFormatterDelay);
312 // subtitle stream setting
313 if (SupportsSubtitleFeature(IPlayerSubtitleCaps::SELECT_STREAM))
314 AddSubtitleStreams(groupSubtitles, SETTING_SUBTITLE_STREAM);
316 // subtitle browser setting
317 if (SupportsSubtitleFeature(IPlayerSubtitleCaps::EXTERNAL))
318 AddButton(groupSubtitles, SETTING_SUBTITLE_BROWSER, 13250, SettingLevel::Basic);
320 AddButton(groupSubtitles, SETTING_SUBTITLE_SEARCH, 24134, SettingLevel::Basic);
322 // subtitle stream setting
323 AddButton(groupSaveAsDefault, SETTING_MAKE_DEFAULT, 12376, SettingLevel::Basic);
326 bool CGUIDialogSubtitleSettings::SupportsSubtitleFeature(IPlayerSubtitleCaps feature)
328 for (IPlayerSubtitleCaps cap : m_subtitleCapabilities)
330 if (cap == feature || cap == IPlayerSubtitleCaps::ALL)
331 return true;
333 return false;
336 void CGUIDialogSubtitleSettings::AddSubtitleStreams(const std::shared_ptr<CSettingGroup>& group,
337 const std::string& settingId)
339 if (group == NULL || settingId.empty())
340 return;
342 auto& components = CServiceBroker::GetAppComponents();
343 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
345 m_subtitleStream = appPlayer->GetSubtitle();
346 if (m_subtitleStream < 0)
347 m_subtitleStream = 0;
349 m_subtitleStreamSetting = AddList(group, settingId, 462, SettingLevel::Basic, m_subtitleStream, SubtitleStreamsOptionFiller, 462);
352 void CGUIDialogSubtitleSettings::SubtitleStreamsOptionFiller(
353 const SettingConstPtr& setting,
354 std::vector<IntegerSettingOption>& list,
355 int& current,
356 void* data)
358 const auto& components = CServiceBroker::GetAppComponents();
359 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
361 int subtitleStreamCount = appPlayer->GetSubtitleCount();
363 // cycle through each subtitle and add it to our entry list
364 for (int i = 0; i < subtitleStreamCount; ++i)
366 SubtitleStreamInfo info;
367 appPlayer->GetSubtitleStreamInfo(i, info);
369 std::string strItem;
370 std::string strLanguage;
372 if (!g_LangCodeExpander.Lookup(info.language, strLanguage))
373 strLanguage = g_localizeStrings.Get(13205); // Unknown
375 if (info.name.length() == 0)
376 strItem = strLanguage;
377 else
378 strItem = StringUtils::Format("{} - {}", strLanguage, info.name);
380 strItem += FormatFlags(info.flags);
381 strItem += StringUtils::Format(" ({}/{})", i + 1, subtitleStreamCount);
383 list.emplace_back(strItem, i);
386 // no subtitle streams - just add a "None" entry
387 if (list.empty())
389 list.emplace_back(g_localizeStrings.Get(231), -1);
390 current = -1;
394 std::string CGUIDialogSubtitleSettings::SettingFormatterDelay(
395 const std::shared_ptr<const CSettingControlSlider>& control,
396 const CVariant& value,
397 const CVariant& minimum,
398 const CVariant& step,
399 const CVariant& maximum)
401 if (!value.isDouble())
402 return "";
404 float fValue = value.asFloat();
405 float fStep = step.asFloat();
407 if (fabs(fValue) < 0.5f * fStep)
408 return StringUtils::Format(g_localizeStrings.Get(22003), 0.0);
409 if (fValue < 0)
410 return StringUtils::Format(g_localizeStrings.Get(22004), fabs(fValue));
412 return StringUtils::Format(g_localizeStrings.Get(22005), fValue);
415 std::string CGUIDialogSubtitleSettings::FormatFlags(StreamFlags flags)
417 std::vector<std::string> localizedFlags;
418 if (flags & StreamFlags::FLAG_DEFAULT)
419 localizedFlags.emplace_back(g_localizeStrings.Get(39105));
420 if (flags & StreamFlags::FLAG_FORCED)
421 localizedFlags.emplace_back(g_localizeStrings.Get(39106));
422 if (flags & StreamFlags::FLAG_HEARING_IMPAIRED)
423 localizedFlags.emplace_back(g_localizeStrings.Get(39107));
424 if (flags & StreamFlags::FLAG_VISUAL_IMPAIRED)
425 localizedFlags.emplace_back(g_localizeStrings.Get(39108));
426 if (flags & StreamFlags::FLAG_ORIGINAL)
427 localizedFlags.emplace_back(g_localizeStrings.Get(39111));
429 std::string formated = StringUtils::Join(localizedFlags, ", ");
431 if (!formated.empty())
432 formated = StringUtils::Format(" [{}]", formated);
434 return formated;