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.
9 #include "GUIDialogSubtitleSettings.h"
12 #include "GUIDialogSubtitles.h"
13 #include "GUIPassword.h"
14 #include "ServiceBroker.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"
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")
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
)
85 return CGUIDialogSettingsManualBase::OnMessage(message
);
88 void CGUIDialogSubtitleSettings::OnSettingChanged(const std::shared_ptr
<const CSetting
>& setting
)
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();
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()
124 for (const auto& vfsAddon
: CServiceBroker::GetVFSAddonCache().GetAddonInstances())
126 if (vfsAddon
->ID() == "vfs.rar" || vfsAddon
->ID() == "vfs.libarchive")
127 extras
+= '|' + vfsAddon
->GetExtensions();
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
))
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";
149 VECSOURCES
shares(*CMediaSourceSettings::GetInstance().GetSources("video"));
150 if (CMediaSettings::GetInstance().GetAdditionalSubtitleDirectoryChecked() != -1 && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SUBTITLES_CUSTOMPATH
).empty())
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");
179 void CGUIDialogSubtitleSettings::OnSettingAction(const std::shared_ptr
<const CSetting
>& setting
)
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
);
198 else if (settingId
== SETTING_SUBTITLE_SEARCH
)
200 auto dialog
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogSubtitles
>(WINDOW_DIALOG_SUBTITLES
);
204 m_subtitleStreamSetting
->UpdateDynamicOptions();
207 else if (settingId
== SETTING_MAKE_DEFAULT
)
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() != LOCK_MODE_EVERYONE
)
219 // prompt user if they are sure
220 if (!CGUIDialogYesNo::ShowAndGetInput(CVariant
{12376}, CVariant
{12377}))
223 // reset the settings
228 db
.EraseAllVideoSettings();
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();
240 void CGUIDialogSubtitleSettings::SetupView()
242 CGUIDialogSettingsManualBase::SetupView();
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");
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");
271 const std::shared_ptr
<CSettingGroup
> groupSubtitles
= AddGroup(category
);
272 if (groupSubtitles
== NULL
)
274 CLog::Log(LOGERROR
, "CGUIDialogSubtitleSettings: unable to setup settings");
277 const std::shared_ptr
<CSettingGroup
> groupSaveAsDefault
= AddGroup(category
);
278 if (groupSaveAsDefault
== NULL
)
280 CLog::Log(LOGERROR
, "CGUIDialogSubtitleSettings: unable to setup settings");
284 bool usePopup
= g_SkinInfo
->HasSkinFile("DialogSlider.xml");
286 const CVideoSettings videoSettings
= appPlayer
->GetVideoSettings();
288 if (appPlayer
->HasPlayer())
290 appPlayer
->GetSubtitleCapabilities(m_subtitleCapabilities
);
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(IPC_SUBS_OFFSET
))
302 std::shared_ptr
<CSettingNumber
> settingSubtitleDelay
= AddSlider(groupSubtitles
, SETTING_SUBTITLE_DELAY
, 22006, SettingLevel::Basic
, videoSettings
.m_SubtitleDelay
, 0, -CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoSubsDelayRange
, 0.1f
, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoSubsDelayRange
, 22006, usePopup
);
303 std::static_pointer_cast
<CSettingControlSlider
>(settingSubtitleDelay
->GetControl())->SetFormatter(SettingFormatterDelay
);
306 // subtitle stream setting
307 if (SupportsSubtitleFeature(IPC_SUBS_SELECT
))
308 AddSubtitleStreams(groupSubtitles
, SETTING_SUBTITLE_STREAM
);
310 // subtitle browser setting
311 if (SupportsSubtitleFeature(IPC_SUBS_EXTERNAL
))
312 AddButton(groupSubtitles
, SETTING_SUBTITLE_BROWSER
, 13250, SettingLevel::Basic
);
314 AddButton(groupSubtitles
, SETTING_SUBTITLE_SEARCH
, 24134, SettingLevel::Basic
);
316 // subtitle stream setting
317 AddButton(groupSaveAsDefault
, SETTING_MAKE_DEFAULT
, 12376, SettingLevel::Basic
);
320 bool CGUIDialogSubtitleSettings::SupportsSubtitleFeature(int feature
)
322 for (auto item
: m_subtitleCapabilities
)
324 if (item
== feature
|| item
== IPC_SUBS_ALL
)
330 void CGUIDialogSubtitleSettings::AddSubtitleStreams(const std::shared_ptr
<CSettingGroup
>& group
,
331 const std::string
& settingId
)
333 if (group
== NULL
|| settingId
.empty())
336 auto& components
= CServiceBroker::GetAppComponents();
337 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
339 m_subtitleStream
= appPlayer
->GetSubtitle();
340 if (m_subtitleStream
< 0)
341 m_subtitleStream
= 0;
343 m_subtitleStreamSetting
= AddList(group
, settingId
, 462, SettingLevel::Basic
, m_subtitleStream
, SubtitleStreamsOptionFiller
, 462);
346 void CGUIDialogSubtitleSettings::SubtitleStreamsOptionFiller(
347 const SettingConstPtr
& setting
,
348 std::vector
<IntegerSettingOption
>& list
,
352 const auto& components
= CServiceBroker::GetAppComponents();
353 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
355 int subtitleStreamCount
= appPlayer
->GetSubtitleCount();
357 // cycle through each subtitle and add it to our entry list
358 for (int i
= 0; i
< subtitleStreamCount
; ++i
)
360 SubtitleStreamInfo info
;
361 appPlayer
->GetSubtitleStreamInfo(i
, info
);
364 std::string strLanguage
;
366 if (!g_LangCodeExpander
.Lookup(info
.language
, strLanguage
))
367 strLanguage
= g_localizeStrings
.Get(13205); // Unknown
369 if (info
.name
.length() == 0)
370 strItem
= strLanguage
;
372 strItem
= StringUtils::Format("{} - {}", strLanguage
, info
.name
);
374 strItem
+= FormatFlags(info
.flags
);
375 strItem
+= StringUtils::Format(" ({}/{})", i
+ 1, subtitleStreamCount
);
377 list
.emplace_back(strItem
, i
);
380 // no subtitle streams - just add a "None" entry
383 list
.emplace_back(g_localizeStrings
.Get(231), -1);
388 std::string
CGUIDialogSubtitleSettings::SettingFormatterDelay(
389 const std::shared_ptr
<const CSettingControlSlider
>& control
,
390 const CVariant
& value
,
391 const CVariant
& minimum
,
392 const CVariant
& step
,
393 const CVariant
& maximum
)
395 if (!value
.isDouble())
398 float fValue
= value
.asFloat();
399 float fStep
= step
.asFloat();
401 if (fabs(fValue
) < 0.5f
* fStep
)
402 return StringUtils::Format(g_localizeStrings
.Get(22003), 0.0);
404 return StringUtils::Format(g_localizeStrings
.Get(22004), fabs(fValue
));
406 return StringUtils::Format(g_localizeStrings
.Get(22005), fValue
);
409 std::string
CGUIDialogSubtitleSettings::FormatFlags(StreamFlags flags
)
411 std::vector
<std::string
> localizedFlags
;
412 if (flags
& StreamFlags::FLAG_DEFAULT
)
413 localizedFlags
.emplace_back(g_localizeStrings
.Get(39105));
414 if (flags
& StreamFlags::FLAG_FORCED
)
415 localizedFlags
.emplace_back(g_localizeStrings
.Get(39106));
416 if (flags
& StreamFlags::FLAG_HEARING_IMPAIRED
)
417 localizedFlags
.emplace_back(g_localizeStrings
.Get(39107));
418 if (flags
& StreamFlags::FLAG_VISUAL_IMPAIRED
)
419 localizedFlags
.emplace_back(g_localizeStrings
.Get(39108));
421 std::string formated
= StringUtils::Join(localizedFlags
, ", ");
423 if (!formated
.empty())
424 formated
= StringUtils::Format(" [{}]", formated
);