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 "view/GUIViewState.h"
11 #include "AutoSwitch.h"
13 #include "GUIPassword.h"
14 #include "PlayListPlayer.h"
15 #include "ServiceBroker.h"
17 #include "ViewDatabase.h"
18 #include "addons/Addon.h"
19 #include "addons/AddonManager.h"
20 #include "addons/PluginSource.h"
21 #include "addons/addoninfo/AddonType.h"
22 #include "addons/gui/GUIViewStateAddonBrowser.h"
23 #include "dialogs/GUIDialogSelect.h"
24 #include "events/windows/GUIViewStateEventLog.h"
25 #include "favourites/GUIViewStateFavourites.h"
26 #include "games/windows/GUIViewStateWindowGames.h"
27 #include "guilib/GUIComponent.h"
28 #include "guilib/GUIWindowManager.h"
29 #include "guilib/LocalizeStrings.h"
30 #include "guilib/TextureManager.h"
31 #include "music/GUIViewStateMusic.h"
32 #include "pictures/GUIViewStatePictures.h"
33 #include "profiles/ProfileManager.h"
34 #include "programs/GUIViewStatePrograms.h"
35 #include "pvr/windows/GUIViewStatePVR.h"
36 #include "settings/MediaSourceSettings.h"
37 #include "settings/Settings.h"
38 #include "settings/SettingsComponent.h"
39 #include "settings/lib/Setting.h"
40 #include "utils/URIUtils.h"
41 #include "video/GUIViewStateVideo.h"
42 #include "video/VideoUtils.h"
43 #include "view/ViewState.h"
45 #define PROPERTY_SORT_ORDER "sort.order"
46 #define PROPERTY_SORT_ASCENDING "sort.ascending"
49 using namespace ADDON
;
52 std::string
CGUIViewState::m_strPlaylistDirectory
;
53 VECSOURCES
CGUIViewState::m_sources
;
55 CGUIViewState
* CGUIViewState::GetViewState(int windowId
, const CFileItemList
& items
)
57 // don't expect derived classes to clear the sources
61 return GetViewState(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(),items
);
63 const CURL url
=items
.GetURL();
65 if (items
.IsAddonsPath())
66 return new CGUIViewStateAddonBrowser(items
);
68 if (items
.HasSortDetails())
69 return new CGUIViewStateFromItems(items
);
71 if (url
.IsProtocol("musicdb"))
72 return new CGUIViewStateMusicDatabase(items
);
74 if (url
.IsProtocol("musicsearch"))
75 return new CGUIViewStateMusicSearch(items
);
77 if (items
.IsSmartPlayList() || url
.IsProtocol("upnp") ||
78 items
.IsLibraryFolder())
80 if (items
.GetContent() == "songs" ||
81 items
.GetContent() == "albums" ||
82 items
.GetContent() == "mixed")
83 return new CGUIViewStateMusicSmartPlaylist(items
);
84 else if (items
.GetContent() == "musicvideos")
85 return new CGUIViewStateVideoMusicVideos(items
);
86 else if (items
.GetContent() == "tvshows")
87 return new CGUIViewStateVideoTVShows(items
);
88 else if (items
.GetContent() == "episodes")
89 return new CGUIViewStateVideoEpisodes(items
);
90 else if (items
.GetContent() == "movies")
91 return new CGUIViewStateVideoMovies(items
);
94 if (url
.IsProtocol("library"))
95 return new CGUIViewStateLibrary(items
);
97 if (items
.IsPlayList())
99 // Playlists (like .strm) can be music or video type
100 if (windowId
== WINDOW_VIDEO_NAV
)
101 return new CGUIViewStateVideoPlaylist(items
);
103 return new CGUIViewStateMusicPlaylist(items
);
106 if (items
.GetPath() == "special://musicplaylists/")
107 return new CGUIViewStateWindowMusicNav(items
);
109 if (url
.IsProtocol("androidapp"))
110 return new CGUIViewStateWindowPrograms(items
);
112 if (url
.IsProtocol("activities"))
113 return new CGUIViewStateEventLog(items
);
115 if (windowId
== WINDOW_MUSIC_NAV
)
116 return new CGUIViewStateWindowMusicNav(items
);
118 if (windowId
== WINDOW_MUSIC_PLAYLIST
)
119 return new CGUIViewStateWindowMusicPlaylist(items
);
121 if (windowId
== WINDOW_MUSIC_PLAYLIST_EDITOR
)
122 return new CGUIViewStateWindowMusicNav(items
);
124 if (windowId
== WINDOW_VIDEO_NAV
)
125 return new CGUIViewStateWindowVideoNav(items
);
127 if (windowId
== WINDOW_VIDEO_PLAYLIST
)
128 return new CGUIViewStateWindowVideoPlaylist(items
);
130 if (windowId
== WINDOW_TV_CHANNELS
)
131 return new CGUIViewStateWindowPVRChannels(windowId
, items
);
133 if (windowId
== WINDOW_TV_RECORDINGS
)
134 return new CGUIViewStateWindowPVRRecordings(windowId
, items
);
136 if (windowId
== WINDOW_TV_GUIDE
)
137 return new CGUIViewStateWindowPVRGuide(windowId
, items
);
139 if (windowId
== WINDOW_TV_TIMERS
)
140 return new CGUIViewStateWindowPVRTimers(windowId
, items
);
142 if (windowId
== WINDOW_TV_TIMER_RULES
)
143 return new CGUIViewStateWindowPVRTimers(windowId
, items
);
145 if (windowId
== WINDOW_TV_SEARCH
)
146 return new CGUIViewStateWindowPVRSearch(windowId
, items
);
148 if (windowId
== WINDOW_RADIO_CHANNELS
)
149 return new CGUIViewStateWindowPVRChannels(windowId
, items
);
151 if (windowId
== WINDOW_RADIO_RECORDINGS
)
152 return new CGUIViewStateWindowPVRRecordings(windowId
, items
);
154 if (windowId
== WINDOW_RADIO_GUIDE
)
155 return new CGUIViewStateWindowPVRGuide(windowId
, items
);
157 if (windowId
== WINDOW_RADIO_TIMERS
)
158 return new CGUIViewStateWindowPVRTimers(windowId
, items
);
160 if (windowId
== WINDOW_RADIO_TIMER_RULES
)
161 return new CGUIViewStateWindowPVRTimers(windowId
, items
);
163 if (windowId
== WINDOW_RADIO_SEARCH
)
164 return new CGUIViewStateWindowPVRSearch(windowId
, items
);
166 if (windowId
== WINDOW_PICTURES
)
167 return new CGUIViewStateWindowPictures(items
);
169 if (windowId
== WINDOW_PROGRAMS
)
170 return new CGUIViewStateWindowPrograms(items
);
172 if (windowId
== WINDOW_GAMES
)
173 return new GAME::CGUIViewStateWindowGames(items
);
175 if (windowId
== WINDOW_ADDON_BROWSER
)
176 return new CGUIViewStateAddonBrowser(items
);
178 if (windowId
== WINDOW_EVENT_LOG
)
179 return new CGUIViewStateEventLog(items
);
181 if (windowId
== WINDOW_FAVOURITES
)
182 return new CGUIViewStateFavourites(items
);
184 // Use as fallback/default
185 return new CGUIViewStateGeneral(items
);
188 CGUIViewState::CGUIViewState(const CFileItemList
& items
) : m_items(items
)
190 m_currentViewAsControl
= 0;
191 m_currentSortMethod
= 0;
192 m_playlist
= PLAYLIST::TYPE_NONE
;
195 CGUIViewState::~CGUIViewState() = default;
197 SortOrder
CGUIViewState::SetNextSortOrder()
199 if (GetSortOrder() == SortOrderAscending
)
200 SetSortOrder(SortOrderDescending
);
202 SetSortOrder(SortOrderAscending
);
206 return GetSortOrder();
209 SortOrder
CGUIViewState::GetSortOrder() const
211 if (m_currentSortMethod
>= 0 && m_currentSortMethod
< (int)m_sortMethods
.size())
212 return m_sortMethods
[m_currentSortMethod
].m_sortDescription
.sortOrder
;
214 return SortOrderAscending
;
217 int CGUIViewState::GetSortOrderLabel() const
219 if (m_currentSortMethod
>= 0 && m_currentSortMethod
< (int)m_sortMethods
.size())
220 if (m_sortMethods
[m_currentSortMethod
].m_sortDescription
.sortOrder
== SortOrderDescending
)
223 return 584; // default sort order label 'Ascending'
226 int CGUIViewState::GetViewAsControl() const
228 return m_currentViewAsControl
;
231 void CGUIViewState::SetViewAsControl(int viewAsControl
)
233 if (viewAsControl
== DEFAULT_VIEW_AUTO
)
234 m_currentViewAsControl
= CAutoSwitch::GetView(m_items
);
236 m_currentViewAsControl
= viewAsControl
;
239 void CGUIViewState::SaveViewAsControl(int viewAsControl
)
241 SetViewAsControl(viewAsControl
);
245 SortDescription
CGUIViewState::GetSortMethod() const
247 SortDescription sorting
;
248 if (m_currentSortMethod
>= 0 && m_currentSortMethod
< (int)m_sortMethods
.size())
249 sorting
= m_sortMethods
[m_currentSortMethod
].m_sortDescription
;
254 bool CGUIViewState::HasMultipleSortMethods() const
256 return m_sortMethods
.size() > 1;
259 int CGUIViewState::GetSortMethodLabel() const
261 if (m_currentSortMethod
>= 0 && m_currentSortMethod
< (int)m_sortMethods
.size())
262 return m_sortMethods
[m_currentSortMethod
].m_buttonLabel
;
264 return 551; // default sort method label 'Name'
267 void CGUIViewState::GetSortMethodLabelMasks(LABEL_MASKS
& masks
) const
269 if (m_currentSortMethod
>= 0 && m_currentSortMethod
< (int)m_sortMethods
.size())
271 masks
= m_sortMethods
[m_currentSortMethod
].m_labelMasks
;
275 masks
.m_strLabelFile
.clear();
276 masks
.m_strLabel2File
.clear();
277 masks
.m_strLabelFolder
.clear();
278 masks
.m_strLabel2Folder
.clear();
281 std::vector
<SortDescription
> CGUIViewState::GetSortDescriptions() const
283 std::vector
<SortDescription
> descriptions
;
284 descriptions
.reserve(m_sortMethods
.size());
285 for (const auto& desc
: m_sortMethods
)
287 descriptions
.emplace_back(desc
.m_sortDescription
);
292 void CGUIViewState::AddSortMethod(SortBy sortBy
, int buttonLabel
, const LABEL_MASKS
&labelMasks
, SortAttribute sortAttributes
/* = SortAttributeNone */, SortOrder sortOrder
/* = SortOrderNone */)
294 AddSortMethod(sortBy
, sortAttributes
, buttonLabel
, labelMasks
, sortOrder
);
297 void CGUIViewState::AddSortMethod(SortBy sortBy
, SortAttribute sortAttributes
, int buttonLabel
, const LABEL_MASKS
&labelMasks
, SortOrder sortOrder
/* = SortOrderNone */)
299 for (size_t i
= 0; i
< m_sortMethods
.size(); ++i
)
300 if (m_sortMethods
[i
].m_sortDescription
.sortBy
== sortBy
)
303 // handle unspecified sort order
304 if (sortBy
!= SortByNone
&& sortOrder
== SortOrderNone
)
306 // the following sort methods are sorted in descending order by default
307 if (sortBy
== SortByDate
|| sortBy
== SortBySize
|| sortBy
== SortByPlaycount
||
308 sortBy
== SortByRating
|| sortBy
== SortByProgramCount
||
309 sortBy
== SortByBitrate
|| sortBy
== SortByListeners
||
310 sortBy
== SortByUserRating
|| sortBy
== SortByLastPlayed
)
311 sortOrder
= SortOrderDescending
;
313 sortOrder
= SortOrderAscending
;
316 GUIViewSortDetails sort
;
317 sort
.m_sortDescription
.sortBy
= sortBy
;
318 sort
.m_sortDescription
.sortOrder
= sortOrder
;
319 sort
.m_sortDescription
.sortAttributes
= sortAttributes
;
320 sort
.m_buttonLabel
= buttonLabel
;
321 sort
.m_labelMasks
= labelMasks
;
322 m_sortMethods
.push_back(sort
);
325 void CGUIViewState::AddSortMethod(SortDescription sortDescription
, int buttonLabel
, const LABEL_MASKS
&labelMasks
)
327 AddSortMethod(sortDescription
.sortBy
, sortDescription
.sortAttributes
, buttonLabel
, labelMasks
, sortDescription
.sortOrder
);
330 void CGUIViewState::SetCurrentSortMethod(int method
)
332 SortBy sortBy
= (SortBy
)method
;
333 if (sortBy
< SortByNone
|| sortBy
> SortByLastUsed
)
336 SetSortMethod(sortBy
);
340 void CGUIViewState::SetSortMethod(SortBy sortBy
, SortOrder sortOrder
/* = SortOrderNone */)
342 for (int i
= 0; i
< (int)m_sortMethods
.size(); ++i
)
344 if (m_sortMethods
[i
].m_sortDescription
.sortBy
== sortBy
)
346 m_currentSortMethod
= i
;
351 if (sortOrder
!= SortOrderNone
)
352 SetSortOrder(sortOrder
);
355 void CGUIViewState::SetSortMethod(SortDescription sortDescription
)
357 return SetSortMethod(sortDescription
.sortBy
, sortDescription
.sortOrder
);
360 bool CGUIViewState::ChooseSortMethod()
363 CGUIDialogSelect
*dialog
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogSelect
>(WINDOW_DIALOG_SELECT
);
367 dialog
->SetHeading(CVariant
{ 39010 }); // Label "Sort by"
368 for (auto &sortMethod
: m_sortMethods
)
369 dialog
->Add(g_localizeStrings
.Get(sortMethod
.m_buttonLabel
));
370 dialog
->SetSelected(m_currentSortMethod
);
372 int newSelected
= dialog
->GetSelectedItem();
373 // check if selection has changed
374 if (!dialog
->IsConfirmed() || newSelected
< 0 || newSelected
== m_currentSortMethod
)
377 m_currentSortMethod
= newSelected
;
382 SortDescription
CGUIViewState::SetNextSortMethod(int direction
/* = 1 */)
384 m_currentSortMethod
+= direction
;
386 if (m_currentSortMethod
>= (int)m_sortMethods
.size())
387 m_currentSortMethod
= 0;
388 if (m_currentSortMethod
< 0)
389 m_currentSortMethod
= m_sortMethods
.size() ? (int)m_sortMethods
.size() - 1 : 0;
393 return GetSortMethod();
396 bool CGUIViewState::HideExtensions()
398 return !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWEXTENSIONS
);
401 bool CGUIViewState::HideParentDirItems()
403 return !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWPARENTDIRITEMS
);
406 bool CGUIViewState::DisableAddSourceButtons()
408 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
410 if (profileManager
->GetCurrentProfile().canWriteSources() || g_passwordManager
.bMasterUser
)
411 return !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWADDSOURCEBUTTONS
);
416 PLAYLIST::Id
CGUIViewState::GetPlaylist() const
421 const std::string
& CGUIViewState::GetPlaylistDirectory()
423 return m_strPlaylistDirectory
;
426 void CGUIViewState::SetPlaylistDirectory(const std::string
& strDirectory
)
428 m_strPlaylistDirectory
= strDirectory
;
429 URIUtils::RemoveSlashAtEnd(m_strPlaylistDirectory
);
432 bool CGUIViewState::IsCurrentPlaylistDirectory(const std::string
& strDirectory
)
434 if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist()!=GetPlaylist())
437 std::string strDir
= strDirectory
;
438 URIUtils::RemoveSlashAtEnd(strDir
);
440 return m_strPlaylistDirectory
== strDir
;
443 bool CGUIViewState::AutoPlayNextItem()
448 std::string
CGUIViewState::GetLockType()
453 std::string
CGUIViewState::GetExtensions()
458 VECSOURCES
& CGUIViewState::GetSources()
463 void CGUIViewState::AddLiveTVSources()
465 VECSOURCES
*sources
= CMediaSourceSettings::GetInstance().GetSources("video");
466 for (IVECSOURCES it
= sources
->begin(); it
!= sources
->end(); ++it
)
468 if (URIUtils::IsLiveTV((*it
).strPath
))
471 source
.strPath
= (*it
).strPath
;
472 source
.strName
= (*it
).strName
;
473 source
.vecPaths
= (*it
).vecPaths
;
474 source
.m_strThumbnailImage
= "";
475 source
.FromNameAndPaths("video", source
.strName
, source
.vecPaths
);
476 m_sources
.push_back(source
);
481 void CGUIViewState::SetSortOrder(SortOrder sortOrder
)
483 if (sortOrder
== SortOrderNone
)
486 if (m_currentSortMethod
< 0 || m_currentSortMethod
>= (int)m_sortMethods
.size())
489 m_sortMethods
[m_currentSortMethod
].m_sortDescription
.sortOrder
= sortOrder
;
492 bool CGUIViewState::AutoPlayNextVideoItem() const
494 if (GetPlaylist() != PLAYLIST::TYPE_VIDEO
)
497 return VIDEO_UTILS::IsAutoPlayNextItem(m_items
.GetContent());
500 void CGUIViewState::LoadViewState(const std::string
&path
, int windowID
)
501 { // get our view state from the db
507 if (db
.GetViewState(path
, windowID
, state
, CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN
)) ||
508 db
.GetViewState(path
, windowID
, state
, ""))
510 SetViewAsControl(state
.m_viewMode
);
511 SetSortMethod(state
.m_sortDescription
);
515 void CGUIViewState::SaveViewToDb(const std::string
&path
, int windowID
, CViewState
*viewState
)
521 SortDescription sorting
= GetSortMethod();
522 CViewState
state(m_currentViewAsControl
, sorting
.sortBy
, sorting
.sortOrder
, sorting
.sortAttributes
);
523 if (viewState
!= NULL
)
526 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
527 db
.SetViewState(path
, windowID
, state
, settings
->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN
));
530 if (viewState
!= NULL
)
534 void CGUIViewState::AddPlaylistOrder(const CFileItemList
& items
, const LABEL_MASKS
& label_masks
)
536 SortBy sortBy
= SortByPlaylistOrder
;
538 SortOrder sortOrder
= SortOrderAscending
;
539 if (items
.HasProperty(PROPERTY_SORT_ORDER
))
541 sortBy
= (SortBy
)items
.GetProperty(PROPERTY_SORT_ORDER
).asInteger();
542 if (sortBy
!= SortByNone
)
544 sortLabel
= SortUtils::GetSortLabel(sortBy
);
545 sortOrder
= items
.GetProperty(PROPERTY_SORT_ASCENDING
).asBoolean() ? SortOrderAscending
: SortOrderDescending
;
549 AddSortMethod(sortBy
, sortLabel
, label_masks
, SortAttributeNone
, sortOrder
);
550 SetSortMethod(sortBy
, sortOrder
);
553 CGUIViewStateGeneral::CGUIViewStateGeneral(const CFileItemList
& items
) : CGUIViewState(items
)
555 AddSortMethod(SortByLabel
, 551, LABEL_MASKS("%F", "%I", "%L", "")); // Filename, size | Foldername, empty
556 SetSortMethod(SortByLabel
);
558 SetViewAsControl(DEFAULT_VIEW_LIST
);
561 CGUIViewStateFromItems::CGUIViewStateFromItems(const CFileItemList
&items
) : CGUIViewState(items
)
563 const std::vector
<GUIViewSortDetails
> &details
= items
.GetSortDetails();
564 for (unsigned int i
= 0; i
< details
.size(); i
++)
566 const GUIViewSortDetails
& sort
= details
[i
];
567 AddSortMethod(sort
.m_sortDescription
, sort
.m_buttonLabel
, sort
.m_labelMasks
);
569 //! @todo Should default sort/view mode be specified?
570 m_currentSortMethod
= 0;
572 SetViewAsControl(DEFAULT_VIEW_LIST
);
574 if (items
.IsPlugin())
576 CURL
url(items
.GetPath());
578 if (CServiceBroker::GetAddonMgr().GetAddon(url
.GetHostName(), addon
, AddonType::PLUGIN
,
579 OnlyEnabled::CHOICE_YES
))
581 const auto plugin
= std::static_pointer_cast
<CPluginSource
>(addon
);
582 if (plugin
->Provides(CPluginSource::AUDIO
))
583 m_playlist
= PLAYLIST::TYPE_MUSIC
;
584 if (plugin
->Provides(CPluginSource::VIDEO
))
585 m_playlist
= PLAYLIST::TYPE_VIDEO
;
589 LoadViewState(items
.GetPath(), CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
592 bool CGUIViewStateFromItems::AutoPlayNextItem()
594 return AutoPlayNextVideoItem();
597 void CGUIViewStateFromItems::SaveViewState()
599 SaveViewToDb(m_items
.GetPath(), CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
602 CGUIViewStateLibrary::CGUIViewStateLibrary(const CFileItemList
&items
) : CGUIViewState(items
)
604 AddSortMethod(SortByNone
, 551, LABEL_MASKS("%F", "%I", "%L", "")); // Filename, Size | Foldername, empty
605 SetSortMethod(SortByNone
);
607 SetViewAsControl(DEFAULT_VIEW_LIST
);
609 LoadViewState(items
.GetPath(), CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
612 void CGUIViewStateLibrary::SaveViewState()
614 SaveViewToDb(m_items
.GetPath(), CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());