[Test] Added tests for CUtil::SplitParams
[xbmc.git] / xbmc / view / GUIViewState.cpp
blobe0cf9d2aca4fafaffacd82cb4a89e6468830be13
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 "view/GUIViewState.h"
11 #include "AutoSwitch.h"
12 #include "FileItem.h"
13 #include "GUIPassword.h"
14 #include "PlayListPlayer.h"
15 #include "ServiceBroker.h"
16 #include "URL.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"
48 using namespace KODI;
49 using namespace ADDON;
50 using namespace PVR;
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
58 m_sources.clear();
60 if (windowId == 0)
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);
102 else
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);
201 else
202 SetSortOrder(SortOrderAscending);
204 SaveViewState();
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)
221 return 585;
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);
235 else
236 m_currentViewAsControl = viewAsControl;
239 void CGUIViewState::SaveViewAsControl(int viewAsControl)
241 SetViewAsControl(viewAsControl);
242 SaveViewState();
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;
251 return sorting;
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;
272 return;
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);
289 return descriptions;
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)
301 return;
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;
312 else
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)
334 return; // invalid
336 SetSortMethod(sortBy);
337 SaveViewState();
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;
347 break;
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);
364 if (!dialog)
365 return false;
366 dialog->Reset();
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);
371 dialog->Open();
372 int newSelected = dialog->GetSelectedItem();
373 // check if selection has changed
374 if (!dialog->IsConfirmed() || newSelected < 0 || newSelected == m_currentSortMethod)
375 return false;
377 m_currentSortMethod = newSelected;
378 SaveViewState();
379 return true;
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;
391 SaveViewState();
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);
413 return true;
416 PLAYLIST::Id CGUIViewState::GetPlaylist() const
418 return m_playlist;
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())
435 return false;
437 std::string strDir = strDirectory;
438 URIUtils::RemoveSlashAtEnd(strDir);
440 return m_strPlaylistDirectory == strDir;
443 bool CGUIViewState::AutoPlayNextItem()
445 return false;
448 std::string CGUIViewState::GetLockType()
450 return "";
453 std::string CGUIViewState::GetExtensions()
455 return "";
458 VECSOURCES& CGUIViewState::GetSources()
460 return m_sources;
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))
470 CMediaSource source;
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)
484 return;
486 if (m_currentSortMethod < 0 || m_currentSortMethod >= (int)m_sortMethods.size())
487 return;
489 m_sortMethods[m_currentSortMethod].m_sortDescription.sortOrder = sortOrder;
492 bool CGUIViewState::AutoPlayNextVideoItem() const
494 if (GetPlaylist() != PLAYLIST::TYPE_VIDEO)
495 return false;
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
502 CViewDatabase db;
503 if (!db.Open())
504 return;
506 CViewState state;
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)
517 CViewDatabase db;
518 if (!db.Open())
519 return;
521 SortDescription sorting = GetSortMethod();
522 CViewState state(m_currentViewAsControl, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes);
523 if (viewState != NULL)
524 *viewState = state;
526 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
527 db.SetViewState(path, windowID, state, settings->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN));
528 db.Close();
530 if (viewState != NULL)
531 settings->Save();
534 void CGUIViewState::AddPlaylistOrder(const CFileItemList& items, const LABEL_MASKS& label_masks)
536 SortBy sortBy = SortByPlaylistOrder;
537 int sortLabel = 559;
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());
577 AddonPtr addon;
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());