[videodb] Remove nested transaction when saving state after stopping PVR playback
[xbmc.git] / xbmc / view / GUIViewState.cpp
blobaa0dc9749ea6dad0dfff4d01b75a45fb65b65bc3
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 "FileItemList.h"
14 #include "GUIPassword.h"
15 #include "PlayListPlayer.h"
16 #include "ServiceBroker.h"
17 #include "URL.h"
18 #include "ViewDatabase.h"
19 #include "addons/Addon.h"
20 #include "addons/AddonManager.h"
21 #include "addons/PluginSource.h"
22 #include "addons/addoninfo/AddonType.h"
23 #include "addons/gui/GUIViewStateAddonBrowser.h"
24 #include "dialogs/GUIDialogSelect.h"
25 #include "events/windows/GUIViewStateEventLog.h"
26 #include "favourites/GUIViewStateFavourites.h"
27 #include "games/windows/GUIViewStateWindowGames.h"
28 #include "guilib/GUIComponent.h"
29 #include "guilib/GUIWindowManager.h"
30 #include "guilib/LocalizeStrings.h"
31 #include "guilib/TextureManager.h"
32 #include "music/GUIViewStateMusic.h"
33 #include "pictures/GUIViewStatePictures.h"
34 #include "playlists/PlayListFileItemClassify.h"
35 #include "profiles/ProfileManager.h"
36 #include "programs/GUIViewStatePrograms.h"
37 #include "pvr/windows/GUIViewStatePVR.h"
38 #include "settings/MediaSourceSettings.h"
39 #include "settings/Settings.h"
40 #include "settings/SettingsComponent.h"
41 #include "settings/lib/Setting.h"
42 #include "utils/URIUtils.h"
43 #include "video/GUIViewStateVideo.h"
44 #include "video/VideoUtils.h"
45 #include "view/ViewState.h"
47 #define PROPERTY_SORT_ORDER "sort.order"
48 #define PROPERTY_SORT_ASCENDING "sort.ascending"
50 using namespace KODI;
51 using namespace ADDON;
52 using namespace PVR;
54 std::string CGUIViewState::m_strPlaylistDirectory;
55 std::vector<CMediaSource> CGUIViewState::m_sources;
57 CGUIViewState* CGUIViewState::GetViewState(int windowId, const CFileItemList& items)
59 // don't expect derived classes to clear the sources
60 m_sources.clear();
62 if (windowId == 0)
63 return GetViewState(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(),items);
65 const CURL url=items.GetURL();
67 if (items.IsAddonsPath())
68 return new CGUIViewStateAddonBrowser(items);
70 if (items.HasSortDetails())
71 return new CGUIViewStateFromItems(items);
73 if (url.IsProtocol("musicdb"))
74 return new CGUIViewStateMusicDatabase(items);
76 if (url.IsProtocol("musicsearch"))
77 return new CGUIViewStateMusicSearch(items);
79 if (PLAYLIST::IsSmartPlayList(items) || url.IsProtocol("upnp") || items.IsLibraryFolder())
81 if (items.GetContent() == "songs" ||
82 items.GetContent() == "albums" ||
83 items.GetContent() == "mixed")
84 return new CGUIViewStateMusicSmartPlaylist(items);
85 else if (items.GetContent() == "musicvideos")
86 return new CGUIViewStateVideoMusicVideos(items);
87 else if (items.GetContent() == "tvshows")
88 return new CGUIViewStateVideoTVShows(items);
89 else if (items.GetContent() == "episodes")
90 return new CGUIViewStateVideoEpisodes(items);
91 else if (items.GetContent() == "movies")
92 return new CGUIViewStateVideoMovies(items);
95 if (url.IsProtocol("library"))
96 return new CGUIViewStateLibrary(items);
98 if (PLAYLIST::IsPlayList(items))
100 // Playlists (like .strm) can be music or video type
101 if (windowId == WINDOW_VIDEO_NAV)
102 return new CGUIViewStateVideoPlaylist(items);
103 else
104 return new CGUIViewStateMusicPlaylist(items);
107 if (items.GetPath() == "special://musicplaylists/")
108 return new CGUIViewStateWindowMusicNav(items);
110 if (url.IsProtocol("androidapp"))
111 return new CGUIViewStateWindowPrograms(items);
113 if (url.IsProtocol("activities"))
114 return new CGUIViewStateEventLog(items);
116 if (windowId == WINDOW_MUSIC_NAV)
117 return new CGUIViewStateWindowMusicNav(items);
119 if (windowId == WINDOW_MUSIC_PLAYLIST)
120 return new CGUIViewStateWindowMusicPlaylist(items);
122 if (windowId == WINDOW_MUSIC_PLAYLIST_EDITOR)
123 return new CGUIViewStateWindowMusicNav(items);
125 if (windowId == WINDOW_VIDEO_NAV)
126 return new CGUIViewStateWindowVideoNav(items);
128 if (windowId == WINDOW_VIDEO_PLAYLIST)
129 return new CGUIViewStateWindowVideoPlaylist(items);
131 if (windowId == WINDOW_TV_CHANNELS)
132 return new CGUIViewStateWindowPVRChannels(windowId, items);
134 if (windowId == WINDOW_TV_RECORDINGS)
135 return new CGUIViewStateWindowPVRRecordings(windowId, items);
137 if (windowId == WINDOW_TV_GUIDE)
138 return new CGUIViewStateWindowPVRGuide(windowId, items);
140 if (windowId == WINDOW_TV_TIMERS)
141 return new CGUIViewStateWindowPVRTimers(windowId, items);
143 if (windowId == WINDOW_TV_TIMER_RULES)
144 return new CGUIViewStateWindowPVRTimers(windowId, items);
146 if (windowId == WINDOW_TV_SEARCH)
147 return new CGUIViewStateWindowPVRSearch(windowId, items);
149 if (windowId == WINDOW_TV_PROVIDERS)
150 return new CGUIViewStateWindowPVRProviders(windowId, items);
152 if (windowId == WINDOW_RADIO_CHANNELS)
153 return new CGUIViewStateWindowPVRChannels(windowId, items);
155 if (windowId == WINDOW_RADIO_RECORDINGS)
156 return new CGUIViewStateWindowPVRRecordings(windowId, items);
158 if (windowId == WINDOW_RADIO_GUIDE)
159 return new CGUIViewStateWindowPVRGuide(windowId, items);
161 if (windowId == WINDOW_RADIO_TIMERS)
162 return new CGUIViewStateWindowPVRTimers(windowId, items);
164 if (windowId == WINDOW_RADIO_TIMER_RULES)
165 return new CGUIViewStateWindowPVRTimers(windowId, items);
167 if (windowId == WINDOW_RADIO_SEARCH)
168 return new CGUIViewStateWindowPVRSearch(windowId, items);
170 if (windowId == WINDOW_RADIO_PROVIDERS)
171 return new CGUIViewStateWindowPVRProviders(windowId, items);
173 if (windowId == WINDOW_PICTURES)
174 return new CGUIViewStateWindowPictures(items);
176 if (windowId == WINDOW_PROGRAMS)
177 return new CGUIViewStateWindowPrograms(items);
179 if (windowId == WINDOW_GAMES)
180 return new GAME::CGUIViewStateWindowGames(items);
182 if (windowId == WINDOW_ADDON_BROWSER)
183 return new CGUIViewStateAddonBrowser(items);
185 if (windowId == WINDOW_EVENT_LOG)
186 return new CGUIViewStateEventLog(items);
188 if (windowId == WINDOW_FAVOURITES)
189 return new CGUIViewStateFavourites(items);
191 // Use as fallback/default
192 return new CGUIViewStateGeneral(items);
195 CGUIViewState::CGUIViewState(const CFileItemList& items) : m_items(items)
197 m_currentViewAsControl = 0;
198 m_currentSortMethod = 0;
199 m_playlist = PLAYLIST::Id::TYPE_NONE;
202 CGUIViewState::~CGUIViewState() = default;
204 SortOrder CGUIViewState::SetNextSortOrder()
206 if (GetSortOrder() == SortOrderAscending)
207 SetSortOrder(SortOrderDescending);
208 else
209 SetSortOrder(SortOrderAscending);
211 SaveViewState();
213 return GetSortOrder();
216 SortOrder CGUIViewState::GetSortOrder() const
218 if (m_currentSortMethod >= 0 && m_currentSortMethod < (int)m_sortMethods.size())
219 return m_sortMethods[m_currentSortMethod].m_sortDescription.sortOrder;
221 return SortOrderAscending;
224 int CGUIViewState::GetSortOrderLabel() const
226 if (m_currentSortMethod >= 0 && m_currentSortMethod < (int)m_sortMethods.size())
227 if (m_sortMethods[m_currentSortMethod].m_sortDescription.sortOrder == SortOrderDescending)
228 return 585;
230 return 584; // default sort order label 'Ascending'
233 int CGUIViewState::GetViewAsControl() const
235 return m_currentViewAsControl;
238 void CGUIViewState::SetViewAsControl(int viewAsControl)
240 if (viewAsControl == DEFAULT_VIEW_AUTO)
241 m_currentViewAsControl = CAutoSwitch::GetView(m_items);
242 else
243 m_currentViewAsControl = viewAsControl;
246 void CGUIViewState::SaveViewAsControl(int viewAsControl)
248 SetViewAsControl(viewAsControl);
249 SaveViewState();
252 SortDescription CGUIViewState::GetSortMethod() const
254 SortDescription sorting;
255 if (m_currentSortMethod >= 0 && m_currentSortMethod < (int)m_sortMethods.size())
256 sorting = m_sortMethods[m_currentSortMethod].m_sortDescription;
258 return sorting;
261 bool CGUIViewState::HasMultipleSortMethods() const
263 return m_sortMethods.size() > 1;
266 int CGUIViewState::GetSortMethodLabel() const
268 if (m_currentSortMethod >= 0 && m_currentSortMethod < (int)m_sortMethods.size())
269 return m_sortMethods[m_currentSortMethod].m_buttonLabel;
271 return 551; // default sort method label 'Name'
274 void CGUIViewState::GetSortMethodLabelMasks(LABEL_MASKS& masks) const
276 if (m_currentSortMethod >= 0 && m_currentSortMethod < (int)m_sortMethods.size())
278 masks = m_sortMethods[m_currentSortMethod].m_labelMasks;
279 return;
282 masks.m_strLabelFile.clear();
283 masks.m_strLabel2File.clear();
284 masks.m_strLabelFolder.clear();
285 masks.m_strLabel2Folder.clear();
288 std::vector<SortDescription> CGUIViewState::GetSortDescriptions() const
290 std::vector<SortDescription> descriptions;
291 descriptions.reserve(m_sortMethods.size());
292 for (const auto& desc : m_sortMethods)
294 descriptions.emplace_back(desc.m_sortDescription);
296 return descriptions;
299 void CGUIViewState::AddSortMethod(SortBy sortBy, int buttonLabel, const LABEL_MASKS &labelMasks, SortAttribute sortAttributes /* = SortAttributeNone */, SortOrder sortOrder /* = SortOrderNone */)
301 AddSortMethod(sortBy, sortAttributes, buttonLabel, labelMasks, sortOrder);
304 void CGUIViewState::AddSortMethod(SortBy sortBy, SortAttribute sortAttributes, int buttonLabel, const LABEL_MASKS &labelMasks, SortOrder sortOrder /* = SortOrderNone */)
306 for (size_t i = 0; i < m_sortMethods.size(); ++i)
307 if (m_sortMethods[i].m_sortDescription.sortBy == sortBy)
308 return;
310 // handle unspecified sort order
311 if (sortBy != SortByNone && sortOrder == SortOrderNone)
313 // the following sort methods are sorted in descending order by default
314 if (sortBy == SortByDate || sortBy == SortBySize || sortBy == SortByPlaycount ||
315 sortBy == SortByRating || sortBy == SortByProgramCount ||
316 sortBy == SortByBitrate || sortBy == SortByListeners ||
317 sortBy == SortByUserRating || sortBy == SortByLastPlayed)
318 sortOrder = SortOrderDescending;
319 else
320 sortOrder = SortOrderAscending;
323 GUIViewSortDetails sort;
324 sort.m_sortDescription.sortBy = sortBy;
325 sort.m_sortDescription.sortOrder = sortOrder;
326 sort.m_sortDescription.sortAttributes = sortAttributes;
327 sort.m_buttonLabel = buttonLabel;
328 sort.m_labelMasks = labelMasks;
329 m_sortMethods.push_back(sort);
332 void CGUIViewState::AddSortMethod(SortDescription sortDescription, int buttonLabel, const LABEL_MASKS &labelMasks)
334 AddSortMethod(sortDescription.sortBy, sortDescription.sortAttributes, buttonLabel, labelMasks, sortDescription.sortOrder);
337 void CGUIViewState::SetCurrentSortMethod(int method)
339 SortBy sortBy = (SortBy)method;
340 if (sortBy < SortByNone || sortBy > SortByLastUsed)
341 return; // invalid
343 SetSortMethod(sortBy);
344 SaveViewState();
347 void CGUIViewState::SetSortMethod(SortBy sortBy, SortOrder sortOrder /* = SortOrderNone */)
349 for (int i = 0; i < (int)m_sortMethods.size(); ++i)
351 if (m_sortMethods[i].m_sortDescription.sortBy == sortBy)
353 m_currentSortMethod = i;
354 break;
358 if (sortOrder != SortOrderNone)
359 SetSortOrder(sortOrder);
362 void CGUIViewState::SetSortMethod(SortDescription sortDescription)
364 return SetSortMethod(sortDescription.sortBy, sortDescription.sortOrder);
367 bool CGUIViewState::ChooseSortMethod()
370 CGUIDialogSelect *dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT);
371 if (!dialog)
372 return false;
373 dialog->Reset();
374 dialog->SetHeading(CVariant{ 39010 }); // Label "Sort by"
375 for (auto &sortMethod : m_sortMethods)
376 dialog->Add(g_localizeStrings.Get(sortMethod.m_buttonLabel));
377 dialog->SetSelected(m_currentSortMethod);
378 dialog->Open();
379 int newSelected = dialog->GetSelectedItem();
380 // check if selection has changed
381 if (!dialog->IsConfirmed() || newSelected < 0 || newSelected == m_currentSortMethod)
382 return false;
384 m_currentSortMethod = newSelected;
385 SaveViewState();
386 return true;
389 SortDescription CGUIViewState::SetNextSortMethod(int direction /* = 1 */)
391 m_currentSortMethod += direction;
393 if (m_currentSortMethod >= (int)m_sortMethods.size())
394 m_currentSortMethod = 0;
395 if (m_currentSortMethod < 0)
396 m_currentSortMethod = m_sortMethods.size() ? (int)m_sortMethods.size() - 1 : 0;
398 SaveViewState();
400 return GetSortMethod();
403 bool CGUIViewState::HideExtensions()
405 return !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWEXTENSIONS);
408 bool CGUIViewState::HideParentDirItems()
410 return !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWPARENTDIRITEMS);
413 bool CGUIViewState::DisableAddSourceButtons()
415 const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();
417 if (profileManager->GetCurrentProfile().canWriteSources() || g_passwordManager.bMasterUser)
418 return !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWADDSOURCEBUTTONS);
420 return true;
423 PLAYLIST::Id CGUIViewState::GetPlaylist() const
425 return m_playlist;
428 const std::string& CGUIViewState::GetPlaylistDirectory()
430 return m_strPlaylistDirectory;
433 void CGUIViewState::SetPlaylistDirectory(const std::string& strDirectory)
435 m_strPlaylistDirectory = strDirectory;
436 URIUtils::RemoveSlashAtEnd(m_strPlaylistDirectory);
439 bool CGUIViewState::IsCurrentPlaylistDirectory(const std::string& strDirectory)
441 if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist()!=GetPlaylist())
442 return false;
444 std::string strDir = strDirectory;
445 URIUtils::RemoveSlashAtEnd(strDir);
447 return m_strPlaylistDirectory == strDir;
450 bool CGUIViewState::AutoPlayNextItem()
452 return false;
455 std::string CGUIViewState::GetLockType()
457 return "";
460 std::string CGUIViewState::GetExtensions()
462 return "";
465 std::vector<CMediaSource>& CGUIViewState::GetSources()
467 return m_sources;
470 void CGUIViewState::AddLiveTVSources()
472 std::vector<CMediaSource>* sources = CMediaSourceSettings::GetInstance().GetSources("video");
473 for (std::vector<CMediaSource>::iterator it = sources->begin(); it != sources->end(); ++it)
475 if (URIUtils::IsLiveTV((*it).strPath))
477 CMediaSource source;
478 source.strPath = (*it).strPath;
479 source.strName = (*it).strName;
480 source.vecPaths = (*it).vecPaths;
481 source.m_strThumbnailImage = "";
482 source.FromNameAndPaths("video", source.strName, source.vecPaths);
483 m_sources.push_back(source);
488 void CGUIViewState::SetSortOrder(SortOrder sortOrder)
490 if (sortOrder == SortOrderNone)
491 return;
493 if (m_currentSortMethod < 0 || m_currentSortMethod >= (int)m_sortMethods.size())
494 return;
496 m_sortMethods[m_currentSortMethod].m_sortDescription.sortOrder = sortOrder;
499 bool CGUIViewState::AutoPlayNextVideoItem() const
501 if (GetPlaylist() != PLAYLIST::Id::TYPE_VIDEO)
502 return false;
504 return VIDEO::UTILS::IsAutoPlayNextItem(m_items.GetContent());
507 void CGUIViewState::LoadViewState(const std::string &path, int windowID)
508 { // get our view state from the db
509 CViewDatabase db;
510 if (!db.Open())
511 return;
513 CViewState state;
514 if (db.GetViewState(path, windowID, state, CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN)) ||
515 db.GetViewState(path, windowID, state, ""))
517 SetViewAsControl(state.m_viewMode);
518 SetSortMethod(state.m_sortDescription);
522 void CGUIViewState::SaveViewToDb(const std::string &path, int windowID, CViewState *viewState)
524 CViewDatabase db;
525 if (!db.Open())
526 return;
528 SortDescription sorting = GetSortMethod();
529 CViewState state(m_currentViewAsControl, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes);
530 if (viewState != NULL)
531 *viewState = state;
533 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
534 db.SetViewState(path, windowID, state, settings->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN));
535 db.Close();
537 if (viewState != NULL)
538 settings->Save();
541 void CGUIViewState::AddPlaylistOrder(const CFileItemList& items, const LABEL_MASKS& label_masks)
543 SortBy sortBy = SortByPlaylistOrder;
544 int sortLabel = 559;
545 SortOrder sortOrder = SortOrderAscending;
546 if (items.HasProperty(PROPERTY_SORT_ORDER))
548 sortBy = (SortBy)items.GetProperty(PROPERTY_SORT_ORDER).asInteger();
549 if (sortBy != SortByNone)
551 sortLabel = SortUtils::GetSortLabel(sortBy);
552 sortOrder = items.GetProperty(PROPERTY_SORT_ASCENDING).asBoolean() ? SortOrderAscending : SortOrderDescending;
556 AddSortMethod(sortBy, sortLabel, label_masks, SortAttributeNone, sortOrder);
557 SetSortMethod(sortBy, sortOrder);
560 CGUIViewStateGeneral::CGUIViewStateGeneral(const CFileItemList& items) : CGUIViewState(items)
562 AddSortMethod(SortByLabel, 551, LABEL_MASKS("%F", "%I", "%L", "")); // Filename, size | Foldername, empty
563 SetSortMethod(SortByLabel);
565 SetViewAsControl(DEFAULT_VIEW_LIST);
568 CGUIViewStateFromItems::CGUIViewStateFromItems(const CFileItemList &items) : CGUIViewState(items)
570 const std::vector<GUIViewSortDetails> &details = items.GetSortDetails();
571 for (unsigned int i = 0; i < details.size(); i++)
573 const GUIViewSortDetails& sort = details[i];
574 AddSortMethod(sort.m_sortDescription, sort.m_buttonLabel, sort.m_labelMasks);
576 //! @todo Should default sort/view mode be specified?
577 m_currentSortMethod = 0;
579 SetViewAsControl(DEFAULT_VIEW_LIST);
581 if (items.IsPlugin())
583 CURL url(items.GetPath());
584 AddonPtr addon;
585 if (CServiceBroker::GetAddonMgr().GetAddon(url.GetHostName(), addon, AddonType::PLUGIN,
586 OnlyEnabled::CHOICE_YES))
588 const auto plugin = std::static_pointer_cast<CPluginSource>(addon);
589 if (plugin->Provides(CPluginSource::AUDIO))
590 m_playlist = PLAYLIST::Id::TYPE_MUSIC;
591 if (plugin->Provides(CPluginSource::VIDEO))
592 m_playlist = PLAYLIST::Id::TYPE_VIDEO;
596 LoadViewState(items.GetPath(), CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
599 bool CGUIViewStateFromItems::AutoPlayNextItem()
601 return AutoPlayNextVideoItem();
604 void CGUIViewStateFromItems::SaveViewState()
606 SaveViewToDb(m_items.GetPath(), CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
609 CGUIViewStateLibrary::CGUIViewStateLibrary(const CFileItemList &items) : CGUIViewState(items)
611 AddSortMethod(SortByNone, 551, LABEL_MASKS("%F", "%I", "%L", "")); // Filename, Size | Foldername, empty
612 SetSortMethod(SortByNone);
614 SetViewAsControl(DEFAULT_VIEW_LIST);
616 LoadViewState(items.GetPath(), CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
619 void CGUIViewStateLibrary::SaveViewState()
621 SaveViewToDb(m_items.GetPath(), CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());